diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f5178379728..e6d5c29aba9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,95 +1,116 @@
name: Test Suite and Doc
-on: [push, pull_request]
+on: [ push, pull_request ]
env:
CARGO_TERM_COLOR: always
- DOC_LLVM_FEATURE: llvm18-0
+ DOC_LLVM_FEATURE: llvm18-1
DOC_LLVM_VERSION: "18.1"
DOC_PATH: target/doc
jobs:
- typos:
- name: Typos
+ lint:
+ name: Linting
runs-on: ubuntu-latest
steps:
- - name: Install Rust Stable
- uses: dtolnay/rust-toolchain@stable
- - name: Install typos
- uses: taiki-e/install-action@typos
- - name: Run typos
- run: typos .
+ - name: Checkout Repo
+ uses: actions/checkout@v4
+ - name: Install Rust Stable
+ uses: dtolnay/rust-toolchain@stable
+ - name: Install typos
+ uses: taiki-e/install-action@typos
+ - name: Check typos
+ run: typos .
+ - name: Check code formatting
+ run: cargo fmt --check
tests:
name: "LLVM ${{ matrix.llvm-version[0] }}: ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
matrix:
llvm-version:
- - ["4.0", "4-0"]
- - ["5.0", "5-0"]
- - ["6.0", "6-0"]
- - ["7.0", "7-0"]
- - ["7.1", "7-0"]
- - ["8.0", "8-0"]
- - ["9.0", "9-0"]
- - ["10.0", "10-0"]
- - ["11.0", "11-0"]
- - ["12.0", "12-0"]
- - ["13.0", "13-0"]
- - ["14.0", "14-0"]
- - ["15.0", "15-0"]
- - ["16.0", "16-0"]
- - ["17.0", "17-0"]
- - ["18.1", "18-0"]
+ - [ "8.0", "8-0" ]
+ - [ "9.0", "9-0" ]
+ - [ "10.0", "10-0" ]
+ - [ "11.0", "11-0" ]
+ - [ "12.0", "12-0" ]
+ - [ "13.0", "13-0" ]
+ - [ "14.0", "14-0" ]
+ - [ "15.0", "15-0" ]
+ - [ "16.0", "16-0" ]
+ - [ "17.0", "17-0" ]
+ - [ "18.1", "18-1" ]
+ - [ "19.1", "19-1", "19" ]
+ - [ "20.1", "20-1", "20" ]
include:
- - os: ubuntu-20.04
- # only use ubuntu-22.04 for llvm 16 and llvm 17
- - os: ubuntu-22.04
- llvm-version: ["16.0", "16-0"]
- - os: ubuntu-22.04
- llvm-version: ["17.0", "17-0"]
+ - os: ubuntu-22.04
steps:
- - name: Checkout Repo
- uses: actions/checkout@v4
- - name: Install LLVM and Clang (LLVM >= 7.1)
- uses: KyleMayes/install-llvm-action@v2
- if: ${{ matrix.llvm-version[0] > 7 }}
- with:
- version: ${{ matrix.llvm-version[0] }}
- - name: Install LLVM and Clang (LLVM <= 7)
- uses: KyleMayes/install-llvm-action@v1
- if: ${{ matrix.llvm-version[0] <= 7 }}
- with:
- version: ${{ matrix.llvm-version[0] }}
- - name: llvm-config
- run: llvm-config --version --bindir --libdir
- - name: Install Rust Stable
- uses: dtolnay/rust-toolchain@stable
- - name: Build
- run: cargo build --release --features llvm${{ matrix.llvm-version[1] }} --verbose
- - name: Run tests
- run: cargo test --release --features llvm${{ matrix.llvm-version[1] }} --verbose
- - name: Build example
- run: cargo build --example kaleidoscope --features llvm${{ matrix.llvm-version[1] }} --verbose
+ - name: Checkout Repo
+ uses: actions/checkout@v4
+ - name: Install Dependencies
+ run: sudo apt update && sudo apt install -y libtinfo5
+ - name: Install LLVM and Clang (LLVM >= 19.1)
+ if: ${{ matrix.llvm-version[0] >= 19 }}
+ run: |
+ sudo apt install --no-install-recommends -y lsb-release wget software-properties-common gnupg
+ wget https://apt.llvm.org/llvm.sh
+ chmod +x llvm.sh
+ sudo ./llvm.sh ${{ matrix.llvm-version[2] }}
+ sudo apt-get update
+ sudo apt install --no-install-recommends -y libllvm${{ matrix.llvm-version[2] }} \
+ llvm-${{ matrix.llvm-version[2] }} \
+ llvm-${{ matrix.llvm-version[2] }}-dev \
+ llvm-${{ matrix.llvm-version[2] }}-runtime \
+ libpolly-${{ matrix.llvm-version[2] }}-dev
+ sudo update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-${{ matrix.llvm-version[2] }} 10
+ - name: Install LLVM and Clang (7.1 <= LLVM <= 19)
+ uses: KyleMayes/install-llvm-action@v2
+ if: ${{ matrix.llvm-version[0] > 7 && matrix.llvm-version[0] <= 19 }}
+ with:
+ version: ${{ matrix.llvm-version[0] }}
+ - name: Install LLVM and Clang (LLVM <= 7)
+ uses: KyleMayes/install-llvm-action@v1
+ if: ${{ matrix.llvm-version[0] <= 7 }}
+ with:
+ version: ${{ matrix.llvm-version[0] }}
+ - name: llvm-config
+ run: llvm-config --version --bindir --libdir
+ - name: Install Rust Stable
+ uses: moonrepo/setup-rust@v1
+ with:
+ bins: cargo-nextest
+ - name: cargo clippy
+ run: cargo clippy --tests --features llvm${{ matrix.llvm-version[1] }} -- -D warnings
+ - name: Build
+ run: cargo build --release --features llvm${{ matrix.llvm-version[1] }} --verbose
+ - name: Run tests
+ run: |
+ cargo nextest run --release --features llvm${{ matrix.llvm-version[1] }} --verbose
+ cargo test --doc --release --features llvm${{ matrix.llvm-version[1] }} --verbose
+ - name: Build examples and run JIT for verification
+ run: |
+ cargo run --example kaleidoscope --features llvm${{ matrix.llvm-version[1] }} --verbose -- --dl --dp --dc -e "(1 + 2 + 3) / (2 + 3)"
+ cargo run --example jit --features llvm${{ matrix.llvm-version[1] }} --verbose
+ cargo run --example jit --features llvm${{ matrix.llvm-version[1] }} --verbose --release
doc:
name: Documentation
- runs-on: ubuntu-20.04
- needs: [typos, tests]
+ runs-on: ubuntu-22.04
+ needs: [ lint, tests ]
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
- - uses: actions/checkout@v4
- - uses: KyleMayes/install-llvm-action@v2
- with:
- version: ${{ env.DOC_LLVM_VERSION }}
- - name: Install Rust Nightly
- uses: dtolnay/rust-toolchain@nightly
- - name: Build Documentation
- run: cargo +nightly doc --features ${{ env.DOC_LLVM_FEATURE }},nightly --verbose
- - name: Doc Index Page Redirection
- run: echo '' > ${{ env.DOC_PATH }}/index.html
- - name: Deploy Documentation
- uses: peaceiris/actions-gh-pages@v3
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ${{ env.DOC_PATH }}
- force_orphan: true
+ - uses: actions/checkout@v4
+ - uses: KyleMayes/install-llvm-action@v2
+ with:
+ version: ${{ env.DOC_LLVM_VERSION }}
+ - name: Install Rust Nightly
+ uses: dtolnay/rust-toolchain@nightly
+ - name: Build Documentation
+ run: cargo +nightly doc --features ${{ env.DOC_LLVM_FEATURE }},nightly --verbose
+ - name: Doc Index Page Redirection
+ run: echo '' > ${{ env.DOC_PATH }}/index.html
+ - name: Deploy Documentation
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ${{ env.DOC_PATH }}
+ force_orphan: true
diff --git a/Cargo.toml b/Cargo.toml
index 3333ab9df93..ea6a8b26de4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "inkwell"
-version = "0.5.0"
+version = "0.6.0"
authors = ["Daniel Kolsoi "]
description = "Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys."
documentation = "https://thedan64.github.io/inkwell/"
@@ -13,33 +13,28 @@ edition = "2021"
[features]
default = ["target-all"]
+typed-pointers = []
# Please update internal_macros::FEATURE_VERSIONS when adding a new LLVM version
-llvm4-0 = ["llvm-sys-40"]
-llvm5-0 = ["llvm-sys-50"]
-llvm6-0 = ["llvm-sys-60"]
-llvm7-0 = ["llvm-sys-70"]
-llvm8-0 = ["llvm-sys-80"]
-llvm9-0 = ["llvm-sys-90"]
-llvm10-0 = ["llvm-sys-100"]
-llvm11-0 = ["llvm-sys-110"]
-llvm12-0 = ["llvm-sys-120"]
-llvm13-0 = ["llvm-sys-130"]
-llvm14-0 = ["llvm-sys-140"]
+llvm8-0 = ["llvm-sys-80", "typed-pointers"]
+llvm9-0 = ["llvm-sys-90", "typed-pointers"]
+llvm10-0 = ["llvm-sys-100", "typed-pointers"]
+llvm11-0 = ["llvm-sys-110", "typed-pointers"]
+llvm12-0 = ["llvm-sys-120", "typed-pointers"]
+llvm13-0 = ["llvm-sys-130", "typed-pointers"]
+llvm14-0 = ["llvm-sys-140", "typed-pointers"]
llvm15-0 = ["llvm-sys-150"]
llvm16-0 = ["llvm-sys-160"]
llvm17-0 = ["llvm-sys-170"]
-llvm18-0 = ["llvm-sys-180"]
+llvm18-1 = ["llvm-sys-181"]
+llvm19-1 = ["llvm-sys-191"]
+llvm20-1 = ["llvm-sys-201"]
# Don't link against LLVM libraries. This is useful if another dependency is
# installing LLVM. See llvm-sys for more details. We can't enable a single
# `no-llvm-linking` feature across the board of llvm versions, as it'll cause
# cargo to try and download and compile them all. See
# https://github.com/rust-lang/cargo/issues/3494
-llvm4-0-no-llvm-linking = ["llvm4-0", "llvm-sys-40/no-llvm-linking"]
-llvm5-0-no-llvm-linking = ["llvm5-0", "llvm-sys-50/no-llvm-linking"]
-llvm6-0-no-llvm-linking = ["llvm6-0", "llvm-sys-60/no-llvm-linking"]
-llvm7-0-no-llvm-linking = ["llvm7-0", "llvm-sys-70/no-llvm-linking"]
llvm8-0-no-llvm-linking = ["llvm8-0", "llvm-sys-80/no-llvm-linking"]
llvm9-0-no-llvm-linking = ["llvm9-0", "llvm-sys-90/no-llvm-linking"]
llvm10-0-no-llvm-linking = ["llvm10-0", "llvm-sys-100/no-llvm-linking"]
@@ -50,7 +45,9 @@ llvm14-0-no-llvm-linking = ["llvm14-0", "llvm-sys-140/no-llvm-linking"]
llvm15-0-no-llvm-linking = ["llvm15-0", "llvm-sys-150/no-llvm-linking"]
llvm16-0-no-llvm-linking = ["llvm16-0", "llvm-sys-160/no-llvm-linking"]
llvm17-0-no-llvm-linking = ["llvm17-0", "llvm-sys-170/no-llvm-linking"]
-llvm18-0-no-llvm-linking = ["llvm18-0", "llvm-sys-180/no-llvm-linking"]
+llvm18-1-no-llvm-linking = ["llvm18-1", "llvm-sys-181/no-llvm-linking"]
+llvm19-1-no-llvm-linking = ["llvm19-1", "llvm-sys-191/no-llvm-linking"]
+llvm20-1-no-llvm-linking = ["llvm20-1", "llvm-sys-201/no-llvm-linking"]
# Linking preference.
# If none of these are enabled, it defaults to force static linking.
@@ -62,7 +59,9 @@ llvm14-0-force-dynamic = ["llvm14-0", "llvm-sys-140/force-dynamic"]
llvm15-0-force-dynamic = ["llvm15-0", "llvm-sys-150/force-dynamic"]
llvm16-0-force-dynamic = ["llvm16-0", "llvm-sys-160/force-dynamic"]
llvm17-0-force-dynamic = ["llvm17-0", "llvm-sys-170/force-dynamic"]
-llvm18-0-force-dynamic = ["llvm18-0", "llvm-sys-180/force-dynamic"]
+llvm18-1-force-dynamic = ["llvm18-1", "llvm-sys-181/force-dynamic"]
+llvm19-1-force-dynamic = ["llvm19-1", "llvm-sys-191/force-dynamic"]
+llvm20-1-force-dynamic = ["llvm20-1", "llvm-sys-201/force-dynamic"]
# Prefer dynamic linking against LLVM libraries. See llvm-sys for more details
llvm12-0-prefer-dynamic = ["llvm12-0", "llvm-sys-120/prefer-dynamic"]
@@ -71,7 +70,9 @@ llvm14-0-prefer-dynamic = ["llvm14-0", "llvm-sys-140/prefer-dynamic"]
llvm15-0-prefer-dynamic = ["llvm15-0", "llvm-sys-150/prefer-dynamic"]
llvm16-0-prefer-dynamic = ["llvm16-0", "llvm-sys-160/prefer-dynamic"]
llvm17-0-prefer-dynamic = ["llvm17-0", "llvm-sys-170/prefer-dynamic"]
-llvm18-0-prefer-dynamic = ["llvm18-0", "llvm-sys-180/prefer-dynamic"]
+llvm18-1-prefer-dynamic = ["llvm18-1", "llvm-sys-181/prefer-dynamic"]
+llvm19-1-prefer-dynamic = ["llvm19-1", "llvm-sys-191/prefer-dynamic"]
+llvm20-1-prefer-dynamic = ["llvm20-1", "llvm-sys-201/prefer-dynamic"]
# Force static linking against LLVM libraries. See llvm-sys for more details
llvm12-0-force-static = ["llvm12-0", "llvm-sys-120/force-static"]
@@ -80,7 +81,9 @@ llvm14-0-force-static = ["llvm14-0", "llvm-sys-140/force-static"]
llvm15-0-force-static = ["llvm15-0", "llvm-sys-150/force-static"]
llvm16-0-force-static = ["llvm16-0", "llvm-sys-160/force-static"]
llvm17-0-force-static = ["llvm17-0", "llvm-sys-170/force-static"]
-llvm18-0-force-static = ["llvm18-0", "llvm-sys-180/force-static"]
+llvm18-1-force-static = ["llvm18-1", "llvm-sys-181/force-static"]
+llvm19-1-force-static = ["llvm19-1", "llvm-sys-191/force-static"]
+llvm20-1-force-static = ["llvm20-1", "llvm-sys-201/force-static"]
# Prefer static linking against LLVM libraries. See llvm-sys for more details
llvm12-0-prefer-static = ["llvm12-0", "llvm-sys-120/prefer-static"]
@@ -89,7 +92,9 @@ llvm14-0-prefer-static = ["llvm14-0", "llvm-sys-140/prefer-static"]
llvm15-0-prefer-static = ["llvm15-0", "llvm-sys-150/prefer-static"]
llvm16-0-prefer-static = ["llvm16-0", "llvm-sys-160/prefer-static"]
llvm17-0-prefer-static = ["llvm17-0", "llvm-sys-170/prefer-static"]
-llvm18-0-prefer-static = ["llvm18-0", "llvm-sys-180/prefer-static"]
+llvm18-1-prefer-static = ["llvm18-1", "llvm-sys-181/prefer-static"]
+llvm19-1-prefer-static = ["llvm19-1", "llvm-sys-191/prefer-static"]
+llvm20-1-prefer-static = ["llvm20-1", "llvm-sys-201/prefer-static"]
# Don't force linking to libffi on non-windows platforms. Without this feature
# inkwell always links to libffi on non-windows platforms.
@@ -135,34 +140,42 @@ experimental = ["static-alloc"]
nightly = ["inkwell_internals/nightly"]
[dependencies]
-inkwell_internals = { path = "./internal_macros", version = "0.10.0" }
+inkwell_internals = { path = "./internal_macros", version = "0.11.0" }
-llvm-sys-40 = { package = "llvm-sys", version = "40.4", optional = true }
-llvm-sys-50 = { package = "llvm-sys", version = "50.4", optional = true }
-llvm-sys-60 = { package = "llvm-sys", version = "60.6", optional = true }
-llvm-sys-70 = { package = "llvm-sys", version = "70.4", optional = true }
llvm-sys-80 = { package = "llvm-sys", version = "80.3", optional = true }
-llvm-sys-90 = { package = "llvm-sys", version = "90.2.1", optional = true }
-llvm-sys-100 = { package = "llvm-sys", version = "100.2.3", optional = true }
-llvm-sys-110 = { package = "llvm-sys", version = "110.0.3", optional = true }
-llvm-sys-120 = { package = "llvm-sys", version = "120.2.4", optional = true }
-llvm-sys-130 = { package = "llvm-sys", version = "130.0.4", optional = true }
-llvm-sys-140 = { package = "llvm-sys", version = "140.0.2", optional = true }
-llvm-sys-150 = { package = "llvm-sys", version = "150.0.3", optional = true }
-llvm-sys-160 = { package = "llvm-sys", version = "160.1.0", optional = true }
+llvm-sys-90 = { package = "llvm-sys", version = "90.2.2", optional = true }
+llvm-sys-100 = { package = "llvm-sys", version = "100.2.4", optional = true }
+llvm-sys-110 = { package = "llvm-sys", version = "110.0.4", optional = true }
+llvm-sys-120 = { package = "llvm-sys", version = "120.3.2", optional = true }
+llvm-sys-130 = { package = "llvm-sys", version = "130.1.2", optional = true }
+llvm-sys-140 = { package = "llvm-sys", version = "140.1.3", optional = true }
+llvm-sys-150 = { package = "llvm-sys", version = "150.2.1", optional = true }
+llvm-sys-160 = { package = "llvm-sys", version = "160.2.1", optional = true }
llvm-sys-170 = { package = "llvm-sys", version = "170.2.0", optional = true }
-llvm-sys-180 = { package = "llvm-sys", version = "181.2.0", optional = true }
+llvm-sys-181 = { package = "llvm-sys", version = "181.2.0", optional = true }
+llvm-sys-191 = { package = "llvm-sys", version = "191.0.0", optional = true }
+llvm-sys-201 = { package = "llvm-sys", version = "201.0.0", optional = true }
either = "1.5"
libc = "0.2"
once_cell = "1.16"
-thiserror = "1.0.48"
+thiserror = "2.0.11"
static-alloc = { version = "0.2", optional = true }
-serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
+serde = { version = "1.0", default-features = false, features = [
+ "derive",
+], optional = true }
[dev-dependencies]
+gumdrop = "0.8.1"
regex = "1"
+[target.'cfg(windows)'.dev-dependencies.windows]
+version = "0.62.2"
+features = [
+ "Win32_System_SystemInformation",
+ "Win32_System_Memory"
+]
+
[badges]
codecov = { repository = "TheDan64/inkwell" }
diff --git a/README.md b/README.md
index 90ba58adb2c..5f7a98f080f 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Inkwell aims to help you pen your own programming languages by safely wrapping l
## Requirements
* Rust 1.56+ (Stable, Beta, or Nightly)
-* One of LLVM 4-18
+* One of LLVM 8-18 (WIP: 19 and 20 are barely supported without extensive tests)
## Usage
@@ -22,7 +22,7 @@ You'll need to point your Cargo.toml to use a single LLVM version feature flag c
```toml
[dependencies]
-inkwell = { version = "0.5.0", features = ["llvm18-0"] }
+inkwell = { version = "0.6.0", features = ["llvm18-1"] }
```
Supported versions:
@@ -62,7 +62,7 @@ struct CodeGen<'ctx> {
}
impl<'ctx> CodeGen<'ctx> {
- fn jit_compile_sum(&self) -> Option> {
+ fn jit_compile_sum(&self) -> Option> {
let i64_type = self.context.i64_type();
let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
let function = self.module.add_function("sum", fn_type, None);
diff --git a/examples/jit.rs b/examples/jit.rs
index eb220a688e5..acef709318f 100644
--- a/examples/jit.rs
+++ b/examples/jit.rs
@@ -19,8 +19,8 @@ struct CodeGen<'ctx> {
execution_engine: ExecutionEngine<'ctx>,
}
-impl<'ctx> CodeGen<'ctx> {
- fn jit_compile_sum(&self) -> Option> {
+impl CodeGen<'_> {
+ fn jit_compile_sum(&self) -> Option> {
let i64_type = self.context.i64_type();
let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
let function = self.module.add_function("sum", fn_type, None);
diff --git a/examples/kaleidoscope/implementation_typed_pointers.rs b/examples/kaleidoscope/implementation_typed_pointers.rs
index acf7c0253fb..7249442a069 100644
--- a/examples/kaleidoscope/implementation_typed_pointers.rs
+++ b/examples/kaleidoscope/implementation_typed_pointers.rs
@@ -11,8 +11,6 @@ use inkwell::types::BasicMetadataTypeEnum;
use inkwell::values::{BasicMetadataValueEnum, BasicValueEnum, FloatValue, FunctionValue, PointerValue};
use inkwell::FloatPredicate;
-use inkwell_internals::llvm_versions;
-
use crate::Token::*;
const ANONYMOUS_FUNCTION_NAME: &str = "anonymous";
@@ -207,7 +205,7 @@ impl<'a> Lexer<'a> {
}
}
-impl<'a> Iterator for Lexer<'a> {
+impl Iterator for Lexer<'_> {
type Item = Token;
/// Lexes the next `Token` and returns it.
@@ -856,12 +854,12 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
builder.build_alloca(self.context.f64_type(), name).unwrap()
}
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> {
self.builder.build_load(ptr, name).unwrap()
}
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> {
self.builder.build_load(self.context.f64_type(), ptr, name).unwrap()
}
@@ -1132,8 +1130,7 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
/// Compiles the specified `Prototype` into an extern LLVM `FunctionValue`.
fn compile_prototype(&self, proto: &Prototype) -> Result, &'static str> {
let ret_type = self.context.f64_type();
- let args_types = std::iter::repeat(ret_type)
- .take(proto.args.len())
+ let args_types = std::iter::repeat_n(ret_type, proto.args.len())
.map(|f| f.into())
.collect::>();
let args_types = args_types.as_slice();
diff --git a/examples/kaleidoscope/main.rs b/examples/kaleidoscope/main.rs
index ecde85f5bc0..04e34484ed1 100644
--- a/examples/kaleidoscope/main.rs
+++ b/examples/kaleidoscope/main.rs
@@ -6,11 +6,11 @@
//! This example is supposed to be ran as a executable, which launches a REPL.
//! The source code is in the following order:
//! - `implementation_typed_pointers.rs`:
-//! Lexer,
-//! Parser,
-//! Compiler.
+//! - Lexer,
+//! - Parser,
+//! - Compiler.
//! - `main.rs`:
-//! Program.
+//! - Program.
//!
//! Both the `Parser` and the `Compiler` may fail, in which case they would return
//! an error represented by `Result`, for easier error reporting.
@@ -34,6 +34,8 @@ use inkwell_internals::llvm_versions;
mod implementation_typed_pointers;
pub use implementation_typed_pointers::*;
+use gumdrop::Options;
+
// ======================================================================================
// PROGRAM ==============================================================================
// ======================================================================================
@@ -55,7 +57,7 @@ pub extern "C" fn putchard(x: f64) -> f64 {
#[no_mangle]
pub extern "C" fn printd(x: f64) -> f64 {
- println!("{}", x);
+ println!("{x}");
x
}
@@ -110,40 +112,34 @@ fn run_passes_on(module: &Module) {
/// Entry point of the program; acts as a REPL.
pub fn main() {
- let mut display_lexer_output = false;
- let mut display_parser_output = false;
- let mut display_compiler_output = false;
-
- for arg in std::env::args() {
- match arg.as_str() {
- "--dl" => display_lexer_output = true,
- "--dp" => display_parser_output = true,
- "--dc" => display_compiler_output = true,
- _ => (),
- }
+ #[derive(Debug, Options)]
+ struct Opts {
+ #[options(help = "print help message")]
+ help: bool,
+ #[options(long = "dl", no_short, help = "Display lexer output")]
+ display_lexer_output: bool,
+ #[options(long = "dp", no_short, help = "Display parser output")]
+ display_parser_output: bool,
+ #[options(long = "dc", no_short, help = "Display compiler output")]
+ display_compiler_output: bool,
+ #[options(short = "e", help = "Display compiler output")]
+ eval: Option,
}
+ let Opts {
+ display_lexer_output,
+ display_parser_output,
+ display_compiler_output,
+ eval,
+ ..
+ } = Opts::parse_args_default_or_exit();
+
let context = Context::create();
let builder = context.create_builder();
let mut previous_exprs = Vec::new();
- loop {
- println!();
- print_flush!("?> ");
-
- // Read input from stdin
- let mut input = String::new();
- io::stdin()
- .read_line(&mut input)
- .expect("Could not read from standard input.");
-
- if input.starts_with("exit") || input.starts_with("quit") {
- break;
- } else if input.chars().all(char::is_whitespace) {
- continue;
- }
-
+ let mut compute = |input: String| {
// Build precedence map
let mut prec = HashMap::with_capacity(6);
@@ -178,7 +174,7 @@ pub fn main() {
if is_anon {
println!("-> Expression parsed: \n{:?}\n", fun.body);
} else {
- println!("-> Function parsed: \n{:?}\n", fun);
+ println!("-> Function parsed: \n{fun:?}\n");
}
}
@@ -192,14 +188,14 @@ pub fn main() {
(function, is_anon)
},
Err(err) => {
- println!("!> Error compiling function: {}", err);
- continue;
+ println!("!> Error compiling function: {err}");
+ return;
},
}
},
Err(err) => {
- println!("!> Error parsing expression: {}", err);
- continue;
+ println!("!> Error parsing expression: {err}");
+ return;
},
};
@@ -218,8 +214,8 @@ pub fn main() {
let compiled_fn = match maybe_fn {
Ok(f) => f,
Err(err) => {
- println!("!> Error during execution: {:?}", err);
- continue;
+ println!("!> Error during execution: {err:?}");
+ return;
},
};
@@ -227,5 +223,28 @@ pub fn main() {
println!("=> {}", compiled_fn.call());
}
}
+ };
+
+ if let Some(input) = eval {
+ compute(format!("{input}\n"));
+ } else {
+ loop {
+ println!();
+ print_flush!("?> ");
+
+ // Read input from stdin
+ let mut input = String::new();
+ io::stdin()
+ .read_line(&mut input)
+ .expect("Could not read from standard input.");
+
+ if input.starts_with("exit") || input.starts_with("quit") {
+ break;
+ } else if input.chars().all(char::is_whitespace) {
+ continue;
+ }
+
+ compute(input);
+ }
}
}
diff --git a/internal_macros/Cargo.toml b/internal_macros/Cargo.toml
index c49467c5227..0367b41a755 100644
--- a/internal_macros/Cargo.toml
+++ b/internal_macros/Cargo.toml
@@ -1,12 +1,12 @@
[package]
authors = ["Daniel Kolsoi "]
description = "Internal macro crate for inkwell"
-edition = "2021"
+edition = "2024"
license = "Apache-2.0"
name = "inkwell_internals"
readme = "README.md"
repository = "https://github.com/TheDan64/inkwell"
-version = "0.10.0"
+version = "0.11.0"
[dependencies]
proc-macro2 = "1.0"
diff --git a/internal_macros/src/cfg.rs b/internal_macros/src/cfg.rs
index 73e1f1e425a..4437c84635c 100644
--- a/internal_macros/src/cfg.rs
+++ b/internal_macros/src/cfg.rs
@@ -9,8 +9,8 @@ use syn::{Lit, RangeLimits};
// This array should match the LLVM features in the top level Cargo manifest
const FEATURE_VERSIONS: &[&str] = &[
- "llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8-0", "llvm9-0", "llvm10-0", "llvm11-0", "llvm12-0", "llvm13-0",
- "llvm14-0", "llvm15-0", "llvm16-0", "llvm17-0", "llvm18-0",
+ "llvm8-0", "llvm9-0", "llvm10-0", "llvm11-0", "llvm12-0", "llvm13-0", "llvm14-0", "llvm15-0", "llvm16-0",
+ "llvm17-0", "llvm18-1", "llvm19-1", "llvm20-1"
];
pub struct VersionRange {
@@ -111,11 +111,22 @@ struct Version {
span: Span,
}
+fn default_minor(major: u32) -> u32 {
+ if major >= 18 {
+ 1
+ } else {
+ 0
+ }
+}
+
impl Parse for Version {
fn parse(input: ParseStream) -> Result {
let lit = input.parse::()?;
let (major, minor) = match &lit {
- Lit::Int(int) => (int.base10_parse()?, 0),
+ Lit::Int(int) => {
+ let major = int.base10_parse()?;
+ (major, default_minor(major))
+ },
Lit::Float(float) => {
let s = float.base10_digits();
let mut parts = s.split('.');
@@ -127,7 +138,7 @@ impl Parse for Version {
let minor = if let Some(minor) = parts.next() {
minor.parse().map_err(|e| syn::Error::new(float.span(), e))?
} else {
- 0
+ default_minor(major)
};
(major, minor)
},
diff --git a/src/attributes.rs b/src/attributes.rs
index ed85374c489..17e0997202c 100644
--- a/src/attributes.rs
+++ b/src/attributes.rs
@@ -73,6 +73,8 @@ impl PartialEq for Attribute {
}
if self.is_type() && other.is_type() {
+ // Seems to be some clippy bug here, but it's not clear why.
+ #[allow(clippy::unit_cmp)]
return self.get_enum_kind_id() == other.get_enum_kind_id()
&& self.get_type_value() == other.get_type_value();
}
@@ -340,7 +342,7 @@ impl Attribute {
/// assert_ne!(type_attribute.get_type_value(), context.i64_type().as_any_type_enum());
/// ```
#[llvm_versions(12..)]
- pub fn get_type_value(&self) -> AnyTypeEnum {
+ pub fn get_type_value(&self) -> AnyTypeEnum<'_> {
assert!(self.is_type()); // FIXME: SubTypes
unsafe { AnyTypeEnum::new(LLVMGetTypeAttributeValue(self.attribute)) }
diff --git a/src/basic_block.rs b/src/basic_block.rs
index 6d039a67bde..da41ee85c38 100644
--- a/src/basic_block.rs
+++ b/src/basic_block.rs
@@ -5,7 +5,7 @@ use llvm_sys::core::{
LLVMGetBasicBlockTerminator, LLVMGetFirstInstruction, LLVMGetFirstUse, LLVMGetLastInstruction,
LLVMGetNextBasicBlock, LLVMGetPreviousBasicBlock, LLVMGetTypeContext, LLVMIsABasicBlock, LLVMIsConstant,
LLVMMoveBasicBlockAfter, LLVMMoveBasicBlockBefore, LLVMPrintTypeToString, LLVMPrintValueToString,
- LLVMRemoveBasicBlockFromParent, LLVMReplaceAllUsesWith, LLVMTypeOf,
+ LLVMRemoveBasicBlockFromParent, LLVMReplaceAllUsesWith, LLVMSetValueName2, LLVMTypeOf,
};
use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
@@ -31,7 +31,12 @@ pub struct BasicBlock<'ctx> {
}
impl<'ctx> BasicBlock<'ctx> {
- pub(crate) unsafe fn new(basic_block: LLVMBasicBlockRef) -> Option {
+ /// Create a basic block from an [LLVMBasicBlockRef].
+ ///
+ /// # Safety
+ ///
+ /// The ref must be valid and point to a valid LLVM basic block.
+ pub unsafe fn new(basic_block: LLVMBasicBlockRef) -> Option {
if basic_block.is_null() {
return None;
}
@@ -288,9 +293,9 @@ impl<'ctx> BasicBlock<'ctx> {
///
/// let void_type = context.void_type();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
///
/// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
@@ -471,18 +476,13 @@ impl<'ctx> BasicBlock<'ctx> {
pub fn set_name(&self, name: &str) {
let c_string = to_c_str(name);
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
- {
- use llvm_sys::core::LLVMSetValueName;
-
- unsafe { LLVMSetValueName(LLVMBasicBlockAsValue(self.basic_block), c_string.as_ptr()) };
- }
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- use llvm_sys::core::LLVMSetValueName2;
-
- unsafe { LLVMSetValueName2(LLVMBasicBlockAsValue(self.basic_block), c_string.as_ptr(), c_string.to_bytes().len()) };
- }
+ unsafe {
+ LLVMSetValueName2(
+ LLVMBasicBlockAsValue(self.basic_block),
+ c_string.as_ptr(),
+ c_string.to_bytes().len(),
+ )
+ };
}
/// Replaces all uses of this basic block with another.
diff --git a/src/builder.rs b/src/builder.rs
index ccdb811428d..29d3f69ad42 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -5,45 +5,57 @@ use llvm_sys::core::LLVMBuildCallWithOperandBundles;
use llvm_sys::core::{
LLVMAddCase, LLVMAddClause, LLVMAddDestination, LLVMBuildAShr, LLVMBuildAdd, LLVMBuildAddrSpaceCast,
LLVMBuildAggregateRet, LLVMBuildAlloca, LLVMBuildAnd, LLVMBuildArrayAlloca, LLVMBuildArrayMalloc,
- LLVMBuildAtomicCmpXchg, LLVMBuildAtomicRMW, LLVMBuildBinOp, LLVMBuildBitCast, LLVMBuildBr, LLVMBuildCast, LLVMBuildCondBr,
- LLVMBuildExactSDiv, LLVMBuildExtractElement, LLVMBuildExtractValue, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFDiv,
- LLVMBuildFMul, LLVMBuildFNeg, LLVMBuildFPCast, LLVMBuildFPExt, LLVMBuildFPToSI, LLVMBuildFPToUI, LLVMBuildFPTrunc,
- LLVMBuildFRem, LLVMBuildFSub, LLVMBuildFence, LLVMBuildFree, LLVMBuildGlobalString, LLVMBuildGlobalStringPtr,
+ LLVMBuildAtomicCmpXchg, LLVMBuildAtomicRMW, LLVMBuildBinOp, LLVMBuildBitCast, LLVMBuildBr, LLVMBuildCast,
+ LLVMBuildCondBr, LLVMBuildExactSDiv, LLVMBuildExtractElement, LLVMBuildExtractValue, LLVMBuildFAdd, LLVMBuildFCmp,
+ LLVMBuildFDiv, LLVMBuildFMul, LLVMBuildFNeg, LLVMBuildFPCast, LLVMBuildFPExt, LLVMBuildFPToSI, LLVMBuildFPToUI,
+ LLVMBuildFPTrunc, LLVMBuildFRem, LLVMBuildFSub, LLVMBuildFence, LLVMBuildFree, LLVMBuildGlobalString,
LLVMBuildICmp, LLVMBuildIndirectBr, LLVMBuildInsertElement, LLVMBuildInsertValue, LLVMBuildIntCast,
LLVMBuildIntToPtr, LLVMBuildIsNotNull, LLVMBuildIsNull, LLVMBuildLShr, LLVMBuildLandingPad, LLVMBuildMalloc,
LLVMBuildMul, LLVMBuildNSWAdd, LLVMBuildNSWMul, LLVMBuildNSWNeg, LLVMBuildNSWSub, LLVMBuildNUWAdd, LLVMBuildNUWMul,
- LLVMBuildNUWNeg, LLVMBuildNUWSub, LLVMBuildNeg, LLVMBuildNot, LLVMBuildOr, LLVMBuildPhi, LLVMBuildPointerCast,
- LLVMBuildPtrToInt, LLVMBuildResume, LLVMBuildRet, LLVMBuildRetVoid, LLVMBuildSDiv, LLVMBuildSExt,
- LLVMBuildSExtOrBitCast, LLVMBuildSIToFP, LLVMBuildSRem, LLVMBuildSelect, LLVMBuildShl, LLVMBuildShuffleVector,
- LLVMBuildStore, LLVMBuildSub, LLVMBuildSwitch, LLVMBuildTrunc, LLVMBuildTruncOrBitCast, LLVMBuildUDiv,
- LLVMBuildUIToFP, LLVMBuildURem, LLVMBuildUnreachable, LLVMBuildVAArg, LLVMBuildXor, LLVMBuildZExt,
- LLVMBuildZExtOrBitCast, LLVMClearInsertionPosition, LLVMDisposeBuilder, LLVMGetInsertBlock, LLVMInsertIntoBuilder,
+ LLVMBuildNUWSub, LLVMBuildNeg, LLVMBuildNot, LLVMBuildOr, LLVMBuildPhi, LLVMBuildPointerCast, LLVMBuildPtrToInt,
+ LLVMBuildResume, LLVMBuildRet, LLVMBuildRetVoid, LLVMBuildSDiv, LLVMBuildSExt, LLVMBuildSExtOrBitCast,
+ LLVMBuildSIToFP, LLVMBuildSRem, LLVMBuildSelect, LLVMBuildShl, LLVMBuildShuffleVector, LLVMBuildStore,
+ LLVMBuildSub, LLVMBuildSwitch, LLVMBuildTrunc, LLVMBuildTruncOrBitCast, LLVMBuildUDiv, LLVMBuildUIToFP,
+ LLVMBuildURem, LLVMBuildUnreachable, LLVMBuildVAArg, LLVMBuildXor, LLVMBuildZExt, LLVMBuildZExtOrBitCast,
+ LLVMClearInsertionPosition, LLVMDisposeBuilder, LLVMGetInsertBlock, LLVMInsertIntoBuilder,
LLVMInsertIntoBuilderWithName, LLVMPositionBuilder, LLVMPositionBuilderAtEnd, LLVMPositionBuilderBefore,
LLVMSetCleanup,
};
+
+#[llvm_versions(..20)]
+use llvm_sys::core::LLVMBuildGlobalStringPtr;
+
+#[llvm_versions(20..)]
+use llvm_sys::core::LLVMBuildGlobalString as LLVMBuildGlobalStringPtr;
+
+#[llvm_versions(..17)]
+use llvm_sys::core::LLVMBuildNUWNeg;
+
+#[llvm_versions(17..)]
+use llvm_sys::core::LLVMSetNUW;
+
#[llvm_versions(..=14)]
-use llvm_sys::core::{
- LLVMBuildCall, LLVMBuildGEP, LLVMBuildInBoundsGEP, LLVMBuildInvoke, LLVMBuildLoad, LLVMBuildPtrDiff,
- LLVMBuildStructGEP,
-};
+#[allow(deprecated)]
+use llvm_sys::core::{LLVMBuildCall, LLVMBuildInvoke};
#[llvm_versions(15..)]
-use llvm_sys::core::{
- LLVMBuildCall2, LLVMBuildGEP2, LLVMBuildInBoundsGEP2, LLVMBuildInvoke2, LLVMBuildLoad2, LLVMBuildPtrDiff2,
- LLVMBuildStructGEP2,
-};
-#[llvm_versions(8..)]
+use llvm_sys::core::{LLVMBuildCall2, LLVMBuildInvoke2};
+#[cfg(all(feature = "typed-pointers", not(feature = "llvm16-0")))]
+#[allow(deprecated)]
+use llvm_sys::core::{LLVMBuildGEP, LLVMBuildInBoundsGEP, LLVMBuildLoad, LLVMBuildPtrDiff, LLVMBuildStructGEP};
+#[cfg(any(not(feature = "typed-pointers"), feature = "llvm16-0"))]
+use llvm_sys::core::{LLVMBuildGEP2, LLVMBuildInBoundsGEP2, LLVMBuildLoad2, LLVMBuildPtrDiff2, LLVMBuildStructGEP2};
use llvm_sys::core::{LLVMBuildIntCast2, LLVMBuildMemCpy, LLVMBuildMemMove, LLVMBuildMemSet};
-
use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef};
use thiserror::Error;
use crate::basic_block::BasicBlock;
-#[llvm_versions(7..=8)]
+#[cfg(feature = "llvm8-0")]
use crate::context::AsContextRef;
-#[llvm_versions(7..)]
use crate::debug_info::DILocation;
use crate::support::to_c_str;
-use crate::types::{AsTypeRef, BasicType, FloatMathType, FunctionType, IntMathType, PointerMathType, PointerType};
+#[llvm_versions(15..)]
+use crate::types::FunctionType;
+use crate::types::{AsTypeRef, BasicType, FloatMathType, IntMathType, PointerMathType, PointerType};
#[llvm_versions(18..)]
use crate::values::operand_bundle::OperandBundle;
#[llvm_versions(..=14)]
@@ -54,6 +66,7 @@ use crate::values::{
PointerMathValue, PointerValue, StructValue, VectorBaseValue,
};
+use crate::error::AlignmentError;
use crate::{AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate};
use std::cell::Cell;
@@ -65,23 +78,35 @@ enum PositionState {
Set,
}
+#[derive(Error, Debug, PartialEq, Eq)]
+pub enum OrderingError {
+ #[error("Both success and failure orderings must be monotonic or stronger.")]
+ WeakerThanMonotic,
+ #[error("The failure ordering may not be stronger than the success ordering.")]
+ WeakerSuccessOrdering,
+ #[error("The failure ordering may not be release or acquire release.")]
+ ReleaseOrAcqRel,
+}
+
/// Errors that can be generated by the Builder. All `build_*` methods return a `Result<_, BuilderError>`, which must be handled.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum BuilderError {
#[error("Builder position is not set")]
UnsetPosition,
#[error("Alignment error")]
- AlignmentError(&'static str),
+ AlignmentError(#[from] crate::error::AlignmentError),
#[error("Aggregate extract index out of range")]
ExtractOutOfRange,
- #[error("Bitwidth of a value is incorrect")]
- BitwidthError(&'static str),
+ #[error("The bitwidth of value must be a power of 2 and greater than or equal to 8.")]
+ BitwidthError,
#[error("Pointee type does not match the value's type")]
- PointeeTypeMismatch(&'static str),
- #[error("Values do not have the same type")]
- ValueTypeMismatch(&'static str),
+ PointeeTypeMismatch,
+ #[error("Values must have the same type")]
+ NotSameType,
+ #[error("Values must have pointer or integer type")]
+ NotPointerOrInteger,
#[error("Ordering error or mismatch")]
- OrderingError(&'static str),
+ OrderingError(OrderingError),
#[error("GEP pointee is not a struct")]
GEPPointee,
#[error("GEP index out of range")]
@@ -244,6 +269,7 @@ impl<'ctx> Builder<'ctx> {
let c_string = to_c_str(name);
let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect();
+ #[allow(deprecated)]
let value = unsafe {
LLVMBuildCall(
self.builder,
@@ -576,9 +602,9 @@ impl<'ctx> Builder<'ctx> {
/// };
///
/// // type of an exception in C++
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_ty = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -614,6 +640,7 @@ impl<'ctx> Builder<'ctx> {
let c_string = to_c_str(name);
let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect();
+ #[allow(deprecated)]
let value = unsafe {
LLVMBuildInvoke(
self.builder,
@@ -697,6 +724,9 @@ impl<'ctx> Builder<'ctx> {
/// };
///
/// // type of an exception in C++
+ /// #[cfg(feature = "typed-pointers")]
+ /// let ptr_type = context.i8_type().ptr_type(AddressSpace::default());
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[ptr_type.into(), i32_type.into()], false);
@@ -806,7 +836,7 @@ impl<'ctx> Builder<'ctx> {
}
/// Landing pads are places where control flow jumps to if a [`Builder::build_invoke`] triggered an exception.
- /// The landing pad will match the exception against its *clauses*. Depending on the clause
+ /// The landing pad will match the exception against its `clauses`. Depending on the clause
/// that is matched, the exception can then be handled, or resumed after some optional cleanup,
/// causing the exception to bubble up.
///
@@ -828,9 +858,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
///
/// // type of an exception in C++
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i8_ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -848,7 +878,7 @@ impl<'ctx> Builder<'ctx> {
/// ```
///
/// * **catch all**: An implementation of the C++ `catch(...)`, which catches all exceptions.
- /// A catch clause with a NULL pointer value will match anything.
+ /// A catch clause with a NULL pointer value will match anything.
///
/// ```no_run
/// use inkwell::context::Context;
@@ -860,9 +890,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
///
/// // type of an exception in C++
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i8_ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -895,9 +925,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
///
/// // type of an exception in C++
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i8_ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -920,7 +950,7 @@ impl<'ctx> Builder<'ctx> {
/// ```
///
/// * **filter**: A filter clause encodes that only some types of exceptions are valid at this
- /// point. A filter clause is made by constructing a clause from a constant array.
+ /// point. A filter clause is made by constructing a clause from a constant array.
///
/// ```no_run
/// use inkwell::context::Context;
@@ -933,9 +963,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
///
/// // type of an exception in C++
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i8_ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -1055,9 +1085,9 @@ impl<'ctx> Builder<'ctx> {
/// };
///
/// // type of an exception in C++
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i8_ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_type = context.i32_type();
/// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -1081,7 +1111,7 @@ impl<'ctx> Builder<'ctx> {
// REVIEW: Doesn't GEP work on array too?
/// 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.
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub unsafe fn build_gep(
&self,
ptr: PointerValue<'ctx>,
@@ -1095,6 +1125,8 @@ impl<'ctx> Builder<'ctx> {
let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = LLVMBuildGEP(
self.builder,
ptr.as_value_ref(),
@@ -1102,13 +1134,22 @@ impl<'ctx> Builder<'ctx> {
index_values.len() as u32,
c_string.as_ptr(),
);
+ #[cfg(feature = "llvm16-0")]
+ let value = LLVMBuildGEP2(
+ self.builder,
+ ptr.get_type().get_element_type().as_type_ref(),
+ ptr.as_value_ref(),
+ index_values.as_mut_ptr(),
+ index_values.len() as u32,
+ c_string.as_ptr(),
+ );
Ok(PointerValue::new(value))
}
// REVIEW: Doesn't GEP work on array too?
/// 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.
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub unsafe fn build_gep>(
&self,
pointee_ty: T,
@@ -1138,7 +1179,7 @@ impl<'ctx> Builder<'ctx> {
// REVIEW: Doesn't GEP work on array too?
// REVIEW: This could be merge in with build_gep via a in_bounds: bool param
/// 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.
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub unsafe fn build_in_bounds_gep(
&self,
ptr: PointerValue<'ctx>,
@@ -1152,6 +1193,8 @@ impl<'ctx> Builder<'ctx> {
let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = LLVMBuildInBoundsGEP(
self.builder,
ptr.as_value_ref(),
@@ -1159,6 +1202,15 @@ impl<'ctx> Builder<'ctx> {
index_values.len() as u32,
c_string.as_ptr(),
);
+ #[cfg(feature = "llvm16-0")]
+ let value = LLVMBuildInBoundsGEP2(
+ self.builder,
+ ptr.get_type().get_element_type().as_type_ref(),
+ ptr.as_value_ref(),
+ index_values.as_mut_ptr(),
+ index_values.len() as u32,
+ c_string.as_ptr(),
+ );
Ok(PointerValue::new(value))
}
@@ -1166,7 +1218,7 @@ impl<'ctx> Builder<'ctx> {
// REVIEW: Doesn't GEP work on array too?
// REVIEW: This could be merge in with build_gep via a in_bounds: bool param
/// 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.
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub unsafe fn build_in_bounds_gep>(
&self,
pointee_ty: T,
@@ -1207,9 +1259,9 @@ impl<'ctx> Builder<'ctx> {
/// let module = context.create_module("struct_gep");
/// let void_type = context.void_type();
/// let i32_ty = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_ty = context.ptr_type(AddressSpace::default());
/// let field_types = &[i32_ty.into(), i32_ty.into()];
/// let struct_ty = context.struct_type(field_types, false);
@@ -1229,7 +1281,7 @@ impl<'ctx> Builder<'ctx> {
/// assert!(builder.build_struct_gep(struct_ptr, 1, "struct_gep").is_ok());
/// assert!(builder.build_struct_gep(struct_ptr, 2, "struct_gep").is_err());
/// ```
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub fn build_struct_gep(
&self,
ptr: PointerValue<'ctx>,
@@ -1254,7 +1306,19 @@ impl<'ctx> Builder<'ctx> {
let c_string = to_c_str(name);
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = unsafe { LLVMBuildStructGEP(self.builder, ptr.as_value_ref(), index, c_string.as_ptr()) };
+ #[cfg(feature = "llvm16-0")]
+ let value = unsafe {
+ LLVMBuildStructGEP2(
+ self.builder,
+ ptr.get_type().get_element_type().as_type_ref(),
+ ptr.as_value_ref(),
+ index,
+ c_string.as_ptr(),
+ )
+ };
unsafe { Ok(PointerValue::new(value)) }
}
@@ -1273,9 +1337,9 @@ impl<'ctx> Builder<'ctx> {
/// let module = context.create_module("struct_gep");
/// let void_type = context.void_type();
/// let i32_ty = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_ty = context.ptr_type(AddressSpace::default());
/// let field_types = &[i32_ty.into(), i32_ty.into()];
/// let struct_ty = context.struct_type(field_types, false);
@@ -1295,7 +1359,7 @@ impl<'ctx> Builder<'ctx> {
/// assert!(builder.build_struct_gep(struct_ty, struct_ptr, 1, "struct_gep").is_ok());
/// assert!(builder.build_struct_gep(struct_ty, struct_ptr, 2, "struct_gep").is_err());
/// ```
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub fn build_struct_gep>(
&self,
pointee_ty: T,
@@ -1347,9 +1411,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[i32_ptr_type.into(), i32_ptr_type.into()], false);
/// let fn_value = module.add_function("ret", fn_type, None);
@@ -1361,7 +1425,7 @@ impl<'ctx> Builder<'ctx> {
/// builder.build_ptr_diff(i32_ptr_param1, i32_ptr_param2, "diff").unwrap();
/// builder.build_return(None).unwrap();
/// ```
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub fn build_ptr_diff(
&self,
lhs_ptr: PointerValue<'ctx>,
@@ -1372,6 +1436,8 @@ impl<'ctx> Builder<'ctx> {
return Err(BuilderError::UnsetPosition);
}
let c_string = to_c_str(name);
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = unsafe {
LLVMBuildPtrDiff(
self.builder,
@@ -1380,6 +1446,22 @@ impl<'ctx> Builder<'ctx> {
c_string.as_ptr(),
)
};
+ #[cfg(feature = "llvm16-0")]
+ let value = {
+ if lhs_ptr.get_type().as_basic_type_enum() != rhs_ptr.get_type().as_basic_type_enum() {
+ return Err(BuilderError::NotSameType);
+ }
+
+ unsafe {
+ LLVMBuildPtrDiff2(
+ self.builder,
+ lhs_ptr.get_type().get_element_type().as_type_ref(),
+ lhs_ptr.as_value_ref(),
+ rhs_ptr.as_value_ref(),
+ c_string.as_ptr(),
+ )
+ }
+ };
unsafe { Ok(IntValue::new(value)) }
}
@@ -1398,9 +1480,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[i32_ptr_type.into(), i32_ptr_type.into()], false);
/// let fn_value = module.add_function("ret", fn_type, None);
@@ -1412,7 +1494,7 @@ impl<'ctx> Builder<'ctx> {
/// builder.build_ptr_diff(i32_ptr_type, i32_ptr_param1, i32_ptr_param2, "diff").unwrap();
/// builder.build_return(None).unwrap();
/// ```
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub fn build_ptr_diff>(
&self,
pointee_ty: T,
@@ -1467,9 +1549,9 @@ impl<'ctx> Builder<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let i32_seven = i32_type.const_int(7, false);
/// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
@@ -1507,9 +1589,9 @@ impl<'ctx> Builder<'ctx> {
/// let module = context.create_module("ret");
/// let builder = context.create_builder();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = i32_type.fn_type(&[i32_ptr_type.into()], false);
/// let fn_value = module.add_function("ret", fn_type, None);
@@ -1522,14 +1604,25 @@ impl<'ctx> Builder<'ctx> {
///
/// builder.build_return(Some(&pointee)).unwrap();
/// ```
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> Result, BuilderError> {
if self.positioned.get() != PositionState::Set {
return Err(BuilderError::UnsetPosition);
}
let c_string = to_c_str(name);
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = unsafe { LLVMBuildLoad(self.builder, ptr.as_value_ref(), c_string.as_ptr()) };
+ #[cfg(feature = "llvm16-0")]
+ let value = unsafe {
+ LLVMBuildLoad2(
+ self.builder,
+ ptr.get_type().get_element_type().as_type_ref(),
+ ptr.as_value_ref(),
+ c_string.as_ptr(),
+ )
+ };
unsafe { Ok(BasicValueEnum::new(value)) }
}
@@ -1547,9 +1640,9 @@ impl<'ctx> Builder<'ctx> {
/// let module = context.create_module("ret");
/// let builder = context.create_builder();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = i32_type.fn_type(&[i32_ptr_type.into()], false);
/// let fn_value = module.add_function("ret", fn_type, None);
@@ -1562,7 +1655,7 @@ impl<'ctx> Builder<'ctx> {
///
/// builder.build_return(Some(&pointee)).unwrap();
/// ```
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub fn build_load>(
&self,
pointee_ty: T,
@@ -1624,7 +1717,6 @@ impl<'ctx> Builder<'ctx> {
/// Returns an `Err(BuilderError::AlignmentError)` if the source or destination alignments are not a power of 2.
///
/// [`TargetData::ptr_sized_int_type_in_context`](https://thedan64.github.io/inkwell/inkwell/targets/struct.TargetData.html#method.ptr_sized_int_type_in_context) will get you one of those.
- #[llvm_versions(8..)]
pub fn build_memcpy(
&self,
dest: PointerValue<'ctx>,
@@ -1637,15 +1729,15 @@ impl<'ctx> Builder<'ctx> {
return Err(BuilderError::UnsetPosition);
}
if !is_alignment_ok(src_align_bytes) {
- return Err(BuilderError::AlignmentError(
- "The src_align_bytes argument to build_memcpy was not a power of 2.",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::SrcNonPowerOfTwo(
+ src_align_bytes,
+ )));
}
if !is_alignment_ok(dest_align_bytes) {
- return Err(BuilderError::AlignmentError(
- "The dest_align_bytes argument to build_memcpy was not a power of 2.",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::DestNonPowerOfTwo(
+ dest_align_bytes,
+ )));
}
let value = unsafe {
@@ -1672,7 +1764,6 @@ impl<'ctx> Builder<'ctx> {
/// Returns an `Err(BuilderError::AlignmentError)` if the source or destination alignments are not a power of 2 under 2^64.
///
/// [`TargetData::ptr_sized_int_type_in_context`](https://thedan64.github.io/inkwell/inkwell/targets/struct.TargetData.html#method.ptr_sized_int_type_in_context) will get you one of those.
- #[llvm_versions(8..)]
pub fn build_memmove(
&self,
dest: PointerValue<'ctx>,
@@ -1685,15 +1776,15 @@ impl<'ctx> Builder<'ctx> {
return Err(BuilderError::UnsetPosition);
}
if !is_alignment_ok(src_align_bytes) {
- return Err(BuilderError::AlignmentError(
- "The src_align_bytes argument to build_memmove was not a power of 2 under 2^64.",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::SrcNonPowerOfTwo(
+ src_align_bytes,
+ )));
}
if !is_alignment_ok(dest_align_bytes) {
- return Err(BuilderError::AlignmentError(
- "The dest_align_bytes argument to build_memmove was not a power of 2 under 2^64.",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::DestNonPowerOfTwo(
+ dest_align_bytes,
+ )));
}
let value = unsafe {
@@ -1720,7 +1811,6 @@ impl<'ctx> Builder<'ctx> {
/// Returns an `Err(BuilderError::AlignmentError)` if the source alignment is not a power of 2 under 2^64.
///
/// [`TargetData::ptr_sized_int_type_in_context`](https://thedan64.github.io/inkwell/inkwell/targets/struct.TargetData.html#method.ptr_sized_int_type_in_context) will get you one of those.
- #[llvm_versions(8..)]
pub fn build_memset(
&self,
dest: PointerValue<'ctx>,
@@ -1732,9 +1822,9 @@ impl<'ctx> Builder<'ctx> {
return Err(BuilderError::UnsetPosition);
}
if !is_alignment_ok(dest_align_bytes) {
- return Err(BuilderError::AlignmentError(
- "The src_align_bytes argument to build_memmove was not a power of 2 under 2^64.",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::DestNonPowerOfTwo(
+ dest_align_bytes,
+ )));
}
let value = unsafe {
@@ -1758,9 +1848,7 @@ impl<'ctx> Builder<'ctx> {
}
// LLVMBuildMalloc segfaults if ty is unsized
if !ty.is_sized() {
- return Err(BuilderError::AlignmentError(
- "Cannot build malloc call for an unsized type",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::Unsized));
}
let c_string = to_c_str(name);
@@ -1783,9 +1871,7 @@ impl<'ctx> Builder<'ctx> {
}
// LLVMBuildArrayMalloc segfaults if ty is unsized
if !ty.is_sized() {
- return Err(BuilderError::AlignmentError(
- "Cannot build array malloc call for an unsized type",
- ));
+ return Err(BuilderError::AlignmentError(AlignmentError::Unsized));
}
let c_string = to_c_str(name);
@@ -2281,7 +2367,6 @@ impl<'ctx> Builder<'ctx> {
}
/// Like `build_int_cast`, but respects the signedness of the type being cast to.
- #[llvm_versions(8..)]
pub fn build_int_cast_sign_flag>(
&self,
int: T,
@@ -2622,12 +2707,26 @@ impl<'ctx> Builder<'ctx> {
unsafe { Ok(T::new(value)) }
}
- pub fn build_binop>(&self, op: InstructionOpcode, lhs: T, rhs: T, name: &str) -> Result, BuilderError> {
+ pub fn build_binop>(
+ &self,
+ op: InstructionOpcode,
+ lhs: T,
+ rhs: T,
+ name: &str,
+ ) -> Result, BuilderError> {
if self.positioned.get() != PositionState::Set {
return Err(BuilderError::UnsetPosition);
}
let c_string = to_c_str(name);
- let value = unsafe { LLVMBuildBinOp(self.builder, op.into(), lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr()) };
+ let value = unsafe {
+ LLVMBuildBinOp(
+ self.builder,
+ op.into(),
+ lhs.as_value_ref(),
+ rhs.as_value_ref(),
+ c_string.as_ptr(),
+ )
+ };
unsafe { Ok(BasicValueEnum::new(value)) }
}
@@ -2803,12 +2902,27 @@ impl<'ctx> Builder<'ctx> {
}
// SubType: (&self, value: &IntValue, name) -> IntValue {
+ #[llvm_versions(..17)]
pub fn build_int_nuw_neg>(&self, value: T, name: &str) -> Result {
if self.positioned.get() != PositionState::Set {
return Err(BuilderError::UnsetPosition);
}
let c_string = to_c_str(name);
let value = unsafe { LLVMBuildNUWNeg(self.builder, value.as_value_ref(), c_string.as_ptr()) };
+ unsafe { Ok(T::new(value)) }
+ }
+
+ // SubType: (&self, value: &IntValue, name) -> IntValue {
+ #[llvm_versions(17..)]
+ pub fn build_int_nuw_neg>(&self, value: T, name: &str) -> Result {
+ if self.positioned.get() != PositionState::Set {
+ return Err(BuilderError::UnsetPosition);
+ }
+ let c_string = to_c_str(name);
+ let value = unsafe { LLVMBuildNeg(self.builder, value.as_value_ref(), c_string.as_ptr()) };
+ unsafe {
+ LLVMSetNUW(value, true.into());
+ }
unsafe { Ok(T::new(value)) }
}
@@ -2893,21 +3007,9 @@ impl<'ctx> Builder<'ctx> {
///
/// let array_alloca = builder.build_alloca(array_type, "array_alloca").unwrap();
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// let array = builder.build_load(array_alloca, "array_load").unwrap().into_array_value();
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let array = builder.build_load(i32_type, array_alloca, "array_load").unwrap().into_array_value();
///
/// let const_int1 = i32_type.const_int(2, false);
@@ -2976,21 +3078,9 @@ impl<'ctx> Builder<'ctx> {
///
/// let array_alloca = builder.build_alloca(array_type, "array_alloca").unwrap();
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// let array = builder.build_load(array_alloca, "array_load").unwrap().into_array_value();
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let array = builder.build_load(i32_type, array_alloca, "array_load").unwrap().into_array_value();
///
/// let const_int1 = i32_type.const_int(2, false);
@@ -3247,6 +3337,7 @@ impl<'ctx> Builder<'ctx> {
}
pub fn clear_insertion_position(&self) {
+ self.positioned.set(PositionState::NotSet);
unsafe { LLVMClearInsertionPosition(self.builder) }
}
@@ -3395,9 +3486,9 @@ impl<'ctx> Builder<'ctx> {
/// let void_type = context.void_type();
/// let i32_type = context.i32_type();
/// let i32_seven = i32_type.const_int(7, false);
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
/// let fn_value = module.add_function("rmw", fn_type, None);
@@ -3423,21 +3514,12 @@ impl<'ctx> Builder<'ctx> {
// "The type of ‘’ must be an integer type whose bit width is a power of two greater than or equal to eight and less than or equal to a target-specific size limit. The type of the ‘’ operand must be a pointer to that type." -- https://releases.llvm.org/3.6.2/docs/LangRef.html#atomicrmw-instruction
if value.get_type().get_bit_width() < 8 || !value.get_type().get_bit_width().is_power_of_two() {
- return Err(BuilderError::BitwidthError(
- "The bitwidth of value must be a power of 2 and greater than 8.",
- ));
+ return Err(BuilderError::BitwidthError);
}
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
if ptr.get_type().get_element_type() != value.get_type().into() {
- return Err(BuilderError::PointeeTypeMismatch(
- "Pointer's pointee type must match the value's type.",
- ));
+ return Err(BuilderError::PointeeTypeMismatch);
}
let val = unsafe {
@@ -3454,12 +3536,14 @@ impl<'ctx> Builder<'ctx> {
unsafe { Ok(IntValue::new(val)) }
}
- /// Builds a cmpxchg instruction. It allows you to atomically compare and replace memory.
+ /// Builds a [`cmpxchg`](https://llvm.org/docs/LangRef.html#cmpxchg-instruction) instruction.
+ ///
+ /// This instruction allows to atomically compare and replace memory.
///
/// May return one of the following errors:
/// - `Err(BuilderError::PointeeTypeMismatch)` if the pointer does not point to an element of the value type
/// - `Err(BuilderError::ValueTypeMismatch)` if the value to compare and the new values are not of the same type, or if
- /// the value does not have a pointer or integer type
+ /// the value does not have a pointer or integer type
/// - `Err(BuilderError::OrderingError)` if the following conditions are not satisfied:
/// - Both success and failure orderings are not Monotonic or stronger
/// - The failure ordering is stronger than the success ordering
@@ -3474,9 +3558,9 @@ impl<'ctx> Builder<'ctx> {
/// let module = context.create_module("cmpxchg");
/// let void_type = context.void_type();
/// let i32_type = context.i32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let i32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
/// let fn_value = module.add_function("", fn_type, None);
@@ -3489,7 +3573,6 @@ impl<'ctx> Builder<'ctx> {
/// builder.build_cmpxchg(i32_ptr_param, i32_seven, i32_eight, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic).unwrap();
/// builder.build_return(None).unwrap();
/// ```
- // https://llvm.org/docs/LangRef.html#cmpxchg-instruction
pub fn build_cmpxchg>(
&self,
ptr: PointerValue<'ctx>,
@@ -3504,43 +3587,26 @@ impl<'ctx> Builder<'ctx> {
let cmp = cmp.as_basic_value_enum();
let new = new.as_basic_value_enum();
if cmp.get_type() != new.get_type() {
- return Err(BuilderError::ValueTypeMismatch(
- "The value to compare against and the value to replace with must have the same type.",
- ));
+ return Err(BuilderError::NotSameType);
}
if !cmp.is_int_value() && !cmp.is_pointer_value() {
- return Err(BuilderError::ValueTypeMismatch(
- "The values must have pointer or integer type.",
- ));
+ return Err(BuilderError::NotPointerOrInteger);
}
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
if ptr.get_type().get_element_type().as_basic_type_enum() != cmp.get_type() {
- return Err(BuilderError::PointeeTypeMismatch(
- "The pointer does not point to an element of the value type.",
- ));
+ return Err(BuilderError::PointeeTypeMismatch);
}
// "Both ordering parameters must be at least monotonic, the ordering constraint on failure must be no stronger than that on success, and the failure ordering cannot be either release or acq_rel." -- https://llvm.org/docs/LangRef.html#cmpxchg-instruction
if success < AtomicOrdering::Monotonic || failure < AtomicOrdering::Monotonic {
- return Err(BuilderError::OrderingError(
- "Both success and failure orderings must be Monotonic or stronger.",
- ));
+ return Err(BuilderError::OrderingError(OrderingError::WeakerThanMonotic));
}
if failure > success {
- return Err(BuilderError::OrderingError(
- "The failure ordering may not be stronger than the success ordering.",
- ));
+ return Err(BuilderError::OrderingError(OrderingError::WeakerSuccessOrdering));
}
if failure == AtomicOrdering::Release || failure == AtomicOrdering::AcquireRelease {
- return Err(BuilderError::OrderingError(
- "The failure ordering may not be release or acquire release.",
- ));
+ return Err(BuilderError::OrderingError(OrderingError::ReleaseOrAcqRel));
}
let val = unsafe {
@@ -3559,7 +3625,7 @@ impl<'ctx> Builder<'ctx> {
}
/// Set the debug info source location of the instruction currently pointed at by the builder
- #[llvm_versions(7..=8)]
+ #[cfg(feature = "llvm8-0")]
pub fn set_current_debug_location(&self, context: impl AsContextRef<'ctx>, location: DILocation<'ctx>) {
use llvm_sys::core::LLVMMetadataAsValue;
use llvm_sys::core::LLVMSetCurrentDebugLocation;
@@ -3582,7 +3648,6 @@ impl<'ctx> Builder<'ctx> {
/// Get the debug info source location of the instruction currently pointed at by the builder,
/// if available.
- #[llvm_versions(7..)]
pub fn get_current_debug_location(&self) -> Option> {
use llvm_sys::core::LLVMGetCurrentDebugLocation;
use llvm_sys::core::LLVMValueAsMetadata;
@@ -3598,7 +3663,7 @@ impl<'ctx> Builder<'ctx> {
/// Unset the debug info source location of the instruction currently pointed at by the
/// builder. If there isn't any debug info, this is a no-op.
- #[llvm_versions(7..=8)]
+ #[cfg(feature = "llvm8-0")]
pub fn unset_current_debug_location(&self) {
use llvm_sys::core::LLVMSetCurrentDebugLocation;
unsafe {
@@ -3618,12 +3683,12 @@ impl<'ctx> Builder<'ctx> {
}
/// Used by build_memcpy and build_memmove
-#[llvm_versions(8..)]
fn is_alignment_ok(align: u32) -> bool {
// This replicates the assertions LLVM runs.
//
// See https://github.com/TheDan64/inkwell/issues/168
- align > 0 && align.is_power_of_two() && (align as f64).log2() < 64.0
+ // is_power_of_two returns false for 0.
+ align.is_power_of_two()
}
impl Drop for Builder<'_> {
diff --git a/src/context.rs b/src/context.rs
index 82cb783bea1..39fcfce1830 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,29 +1,34 @@
//! A `Context` is an opaque owner and manager of core global data.
-#[llvm_versions(7..)]
use crate::InlineAsmDialect;
use libc::c_void;
-#[llvm_versions(..=6)]
-use llvm_sys::core::LLVMConstInlineAsm;
+#[cfg(all(any(feature = "llvm15-0", feature = "llvm16-0"), feature = "typed-pointers"))]
+use llvm_sys::core::LLVMContextSetOpaquePointers;
#[llvm_versions(12..)]
use llvm_sys::core::LLVMCreateTypeAttribute;
-#[llvm_versions(7..)]
+
use llvm_sys::core::LLVMGetInlineAsm;
#[llvm_versions(12..)]
use llvm_sys::core::LLVMGetTypeByName2;
-#[llvm_versions(6..)]
use llvm_sys::core::LLVMMetadataTypeInContext;
-#[llvm_versions(15..)]
+#[cfg(not(feature = "typed-pointers"))]
use llvm_sys::core::LLVMPointerTypeInContext;
use llvm_sys::core::{
- LLVMAppendBasicBlockInContext, LLVMConstStringInContext, LLVMConstStructInContext, LLVMContextCreate,
- LLVMContextDispose, LLVMContextSetDiagnosticHandler, LLVMCreateBuilderInContext, LLVMCreateEnumAttribute,
- LLVMCreateStringAttribute, LLVMDoubleTypeInContext, LLVMFP128TypeInContext, LLVMFloatTypeInContext,
- LLVMGetGlobalContext, LLVMGetMDKindIDInContext, LLVMHalfTypeInContext, LLVMInsertBasicBlockInContext,
- LLVMInt16TypeInContext, LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext,
- LLVMInt8TypeInContext, LLVMIntTypeInContext, LLVMModuleCreateWithNameInContext, LLVMPPCFP128TypeInContext,
- LLVMStructCreateNamed, LLVMStructTypeInContext, LLVMVoidTypeInContext, LLVMX86FP80TypeInContext,
+ LLVMAppendBasicBlockInContext, LLVMConstStructInContext, LLVMContextCreate, LLVMContextDispose,
+ LLVMContextSetDiagnosticHandler, LLVMCreateBuilderInContext, LLVMCreateEnumAttribute, LLVMCreateStringAttribute,
+ LLVMDoubleTypeInContext, LLVMFP128TypeInContext, LLVMFloatTypeInContext, LLVMGetGlobalContext,
+ LLVMGetMDKindIDInContext, LLVMHalfTypeInContext, LLVMInsertBasicBlockInContext, LLVMInt16TypeInContext,
+ LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext, LLVMInt8TypeInContext, LLVMIntTypeInContext,
+ LLVMModuleCreateWithNameInContext, LLVMPPCFP128TypeInContext, LLVMStructCreateNamed, LLVMStructTypeInContext,
+ LLVMVoidTypeInContext, LLVMX86FP80TypeInContext,
};
+
+#[llvm_versions(..19)]
+use llvm_sys::core::LLVMConstStringInContext;
+
+#[llvm_versions(19..)]
+use llvm_sys::core::LLVMConstStringInContext2;
+
#[allow(deprecated)]
use llvm_sys::core::{LLVMMDNodeInContext, LLVMMDStringInContext};
use llvm_sys::ir_reader::LLVMParseIRInContext;
@@ -41,9 +46,10 @@ use crate::support::{to_c_str, LLVMString};
use crate::targets::TargetData;
#[llvm_versions(12..)]
use crate::types::AnyTypeEnum;
-#[llvm_versions(6..)]
use crate::types::MetadataType;
-use crate::types::{AsTypeRef, BasicTypeEnum, FloatType, FunctionType, IntType, PointerType, StructType, VoidType};
+#[cfg(not(feature = "typed-pointers"))]
+use crate::types::PointerType;
+use crate::types::{AsTypeRef, BasicTypeEnum, FloatType, FunctionType, IntType, StructType, VoidType};
use crate::values::{
ArrayValue, AsValueRef, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, MetadataValue, PointerValue,
StructValue,
@@ -78,6 +84,11 @@ impl ContextImpl {
pub(crate) unsafe fn new(context: LLVMContextRef) -> Self {
assert!(!context.is_null());
+ #[cfg(all(any(feature = "llvm15-0", feature = "llvm16-0"), feature = "typed-pointers"))]
+ unsafe {
+ LLVMContextSetOpaquePointers(context, 0)
+ };
+
ContextImpl(context)
}
@@ -115,14 +126,8 @@ impl ContextImpl {
mut constraints: String,
sideeffects: bool,
alignstack: bool,
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))] dialect: Option<
- InlineAsmDialect,
- >,
+ dialect: Option,
#[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -131,17 +136,6 @@ impl ContextImpl {
)))]
can_throw: bool,
) -> PointerValue<'ctx> {
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
- let value = unsafe {
- LLVMConstInlineAsm(
- ty.as_type_ref(),
- assembly.as_ptr() as *const ::libc::c_char,
- constraints.as_ptr() as *const ::libc::c_char,
- sideeffects as i32,
- alignstack as i32,
- )
- };
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
let value = unsafe {
LLVMGetInlineAsm(
ty.as_type_ref(),
@@ -153,10 +147,6 @@ impl ContextImpl {
alignstack as i32,
dialect.unwrap_or(InlineAsmDialect::ATT).into(),
#[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -205,7 +195,6 @@ impl ContextImpl {
unsafe { IntType::new(LLVMIntTypeInContext(self.0, bits)) }
}
- #[llvm_versions(6..)]
fn metadata_type<'ctx>(&self) -> MetadataType<'ctx> {
unsafe { MetadataType::new(LLVMMetadataTypeInContext(self.0)) }
}
@@ -245,7 +234,7 @@ impl ContextImpl {
unsafe { FloatType::new(LLVMPPCFP128TypeInContext(self.0)) }
}
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
fn ptr_type<'ctx>(&self, address_space: AddressSpace) -> PointerType<'ctx> {
unsafe { PointerType::new(LLVMPointerTypeInContext(self.0, address_space.0)) }
}
@@ -345,7 +334,13 @@ impl ContextImpl {
fn metadata_string<'ctx>(&self, string: &str) -> MetadataValue<'ctx> {
let c_string = to_c_str(string);
- unsafe { MetadataValue::new(LLVMMDStringInContext(self.0, c_string.as_ptr(), c_string.to_bytes().len() as u32)) }
+ unsafe {
+ MetadataValue::new(LLVMMDStringInContext(
+ self.0,
+ c_string.as_ptr(),
+ c_string.to_bytes().len() as u32,
+ ))
+ }
}
fn get_kind_id(&self, key: &str) -> u32 {
@@ -373,6 +368,7 @@ impl ContextImpl {
unsafe { Attribute::new(LLVMCreateTypeAttribute(self.0, kind_id, type_ref.as_type_ref())) }
}
+ #[llvm_versions(..19)]
fn const_string<'ctx>(&self, string: &[u8], null_terminated: bool) -> ArrayValue<'ctx> {
unsafe {
ArrayValue::new(LLVMConstStringInContext(
@@ -384,6 +380,18 @@ impl ContextImpl {
}
}
+ #[llvm_versions(19..)]
+ fn const_string<'ctx>(&self, string: &[u8], null_terminated: bool) -> ArrayValue<'ctx> {
+ unsafe {
+ ArrayValue::new(LLVMConstStringInContext2(
+ self.0,
+ string.as_ptr() as *const ::libc::c_char,
+ string.len(),
+ !null_terminated as i32,
+ ))
+ }
+ }
+
fn set_diagnostic_handler(
&self,
handler: extern "C" fn(LLVMDiagnosticInfoRef, *mut c_void),
@@ -486,7 +494,7 @@ impl Context {
/// let builder = context.create_builder();
/// ```
#[inline]
- pub fn create_builder(&self) -> Builder {
+ pub fn create_builder(&self) -> Builder<'_> {
self.context.create_builder()
}
@@ -501,7 +509,7 @@ impl Context {
/// let module = context.create_module("my_module");
/// ```
#[inline]
- pub fn create_module(&self, name: &str) -> Module {
+ pub fn create_module(&self, name: &str) -> Module<'_> {
self.context.create_module(name)
}
@@ -532,7 +540,7 @@ impl Context {
// a double free in valgrind when the MemoryBuffer drops so we are `forget`ting MemoryBuffer here
// for now until we can confirm this is the correct thing to do
#[inline]
- pub fn create_module_from_ir(&self, memory_buffer: MemoryBuffer) -> Result {
+ pub fn create_module_from_ir(&self, memory_buffer: MemoryBuffer) -> Result, LLVMString> {
self.context.create_module_from_ir(memory_buffer)
}
@@ -559,12 +567,8 @@ impl Context {
/// "=r,{rax},{rdi}".to_string(),
/// true,
/// false,
- /// #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))] None,
+ /// None,
/// #[cfg(not(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
/// feature = "llvm8-0",
/// feature = "llvm9-0",
/// feature = "llvm10-0",
@@ -576,10 +580,6 @@ impl Context {
/// let params = &[context.i64_type().const_int(60, false).into(), context.i64_type().const_int(1, false).into()];
///
/// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
/// feature = "llvm8-0",
/// feature = "llvm9-0",
/// feature = "llvm10-0",
@@ -594,7 +594,7 @@ impl Context {
/// builder.build_call(callable_value, params, "exit").unwrap();
/// }
///
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1"))]
/// builder.build_indirect_call(asm_fn, asm, params, "exit").unwrap();
///
/// builder.build_return(None).unwrap();
@@ -607,14 +607,8 @@ impl Context {
constraints: String,
sideeffects: bool,
alignstack: bool,
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))] dialect: Option<
- InlineAsmDialect,
- >,
+ dialect: Option,
#[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -629,13 +623,8 @@ impl Context {
constraints,
sideeffects,
alignstack,
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
dialect,
#[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -659,7 +648,7 @@ impl Context {
/// assert_eq!(void_type.get_context(), context);
/// ```
#[inline]
- pub fn void_type(&self) -> VoidType {
+ pub fn void_type(&self) -> VoidType<'_> {
self.context.void_type()
}
@@ -677,7 +666,7 @@ impl Context {
/// assert_eq!(bool_type.get_context(), context);
/// ```
#[inline]
- pub fn bool_type(&self) -> IntType {
+ pub fn bool_type(&self) -> IntType<'_> {
self.context.bool_type()
}
@@ -695,7 +684,7 @@ impl Context {
/// assert_eq!(i8_type.get_context(), context);
/// ```
#[inline]
- pub fn i8_type(&self) -> IntType {
+ pub fn i8_type(&self) -> IntType<'_> {
self.context.i8_type()
}
@@ -713,7 +702,7 @@ impl Context {
/// assert_eq!(i16_type.get_context(), context);
/// ```
#[inline]
- pub fn i16_type(&self) -> IntType {
+ pub fn i16_type(&self) -> IntType<'_> {
self.context.i16_type()
}
@@ -731,7 +720,7 @@ impl Context {
/// assert_eq!(i32_type.get_context(), context);
/// ```
#[inline]
- pub fn i32_type(&self) -> IntType {
+ pub fn i32_type(&self) -> IntType<'_> {
self.context.i32_type()
}
@@ -749,7 +738,7 @@ impl Context {
/// assert_eq!(i64_type.get_context(), context);
/// ```
#[inline]
- pub fn i64_type(&self) -> IntType {
+ pub fn i64_type(&self) -> IntType<'_> {
self.context.i64_type()
}
@@ -767,7 +756,7 @@ impl Context {
/// assert_eq!(i128_type.get_context(), context);
/// ```
#[inline]
- pub fn i128_type(&self) -> IntType {
+ pub fn i128_type(&self) -> IntType<'_> {
self.context.i128_type()
}
@@ -785,7 +774,7 @@ impl Context {
/// assert_eq!(i42_type.get_context(), context);
/// ```
#[inline]
- pub fn custom_width_int_type(&self, bits: u32) -> IntType {
+ pub fn custom_width_int_type(&self, bits: u32) -> IntType<'_> {
self.context.custom_width_int_type(bits)
}
@@ -803,8 +792,7 @@ impl Context {
/// assert_eq!(md_type.get_context(), context);
/// ```
#[inline]
- #[llvm_versions(6..)]
- pub fn metadata_type(&self) -> MetadataType {
+ pub fn metadata_type(&self) -> MetadataType<'_> {
self.context.metadata_type()
}
@@ -826,7 +814,7 @@ impl Context {
/// let int_type = context.ptr_sized_int_type(&target_data, None);
/// ```
#[inline]
- pub fn ptr_sized_int_type(&self, target_data: &TargetData, address_space: Option) -> IntType {
+ pub fn ptr_sized_int_type(&self, target_data: &TargetData, address_space: Option) -> IntType<'_> {
self.context.ptr_sized_int_type(target_data, address_space)
}
@@ -844,7 +832,7 @@ impl Context {
/// assert_eq!(f16_type.get_context(), context);
/// ```
#[inline]
- pub fn f16_type(&self) -> FloatType {
+ pub fn f16_type(&self) -> FloatType<'_> {
self.context.f16_type()
}
@@ -862,7 +850,7 @@ impl Context {
/// assert_eq!(f32_type.get_context(), context);
/// ```
#[inline]
- pub fn f32_type(&self) -> FloatType {
+ pub fn f32_type(&self) -> FloatType<'_> {
self.context.f32_type()
}
@@ -880,7 +868,7 @@ impl Context {
/// assert_eq!(f64_type.get_context(), context);
/// ```
#[inline]
- pub fn f64_type(&self) -> FloatType {
+ pub fn f64_type(&self) -> FloatType<'_> {
self.context.f64_type()
}
@@ -898,7 +886,7 @@ impl Context {
/// assert_eq!(x86_f80_type.get_context(), context);
/// ```
#[inline]
- pub fn x86_f80_type(&self) -> FloatType {
+ pub fn x86_f80_type(&self) -> FloatType<'_> {
self.context.x86_f80_type()
}
@@ -917,7 +905,7 @@ impl Context {
/// ```
// IEEE 754-2008’s binary128 floats according to https://internals.rust-lang.org/t/pre-rfc-introduction-of-half-and-quadruple-precision-floats-f16-and-f128/7521
#[inline]
- pub fn f128_type(&self) -> FloatType {
+ pub fn f128_type(&self) -> FloatType<'_> {
self.context.f128_type()
}
@@ -938,7 +926,7 @@ impl Context {
/// ```
// Two 64 bits according to https://internals.rust-lang.org/t/pre-rfc-introduction-of-half-and-quadruple-precision-floats-f16-and-f128/7521
#[inline]
- pub fn ppc_f128_type(&self) -> FloatType {
+ pub fn ppc_f128_type(&self) -> FloatType<'_> {
self.context.ppc_f128_type()
}
@@ -956,9 +944,9 @@ impl Context {
/// assert_eq!(ptr_type.get_address_space(), AddressSpace::default());
/// assert_eq!(ptr_type.get_context(), context);
/// ```
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
#[inline]
- pub fn ptr_type(&self, address_space: AddressSpace) -> PointerType {
+ pub fn ptr_type(&self, address_space: AddressSpace) -> PointerType<'_> {
self.context.ptr_type(address_space)
}
@@ -978,7 +966,7 @@ impl Context {
/// ```
// REVIEW: AnyType but VoidType? FunctionType?
#[inline]
- pub fn struct_type(&self, field_types: &[BasicTypeEnum], packed: bool) -> StructType {
+ pub fn struct_type<'ctx>(&'ctx self, field_types: &[BasicTypeEnum], packed: bool) -> StructType<'ctx> {
self.context.struct_type(field_types, packed)
}
@@ -997,7 +985,7 @@ impl Context {
/// assert_eq!(struct_type.get_field_types(), &[]);
/// ```
#[inline]
- pub fn opaque_struct_type(&self, name: &str) -> StructType {
+ pub fn opaque_struct_type<'ctx>(&'ctx self, name: &str) -> StructType<'ctx> {
self.context.opaque_struct_type(name)
}
@@ -1039,7 +1027,7 @@ impl Context {
/// assert_eq!(const_struct.get_type().get_field_types(), &[i16_type.into(), f32_type.into()]);
/// ```
#[inline]
- pub fn const_struct(&self, values: &[BasicValueEnum], packed: bool) -> StructValue {
+ pub fn const_struct<'ctx>(&'ctx self, values: &[BasicValueEnum], packed: bool) -> StructValue<'ctx> {
self.context.const_struct(values, packed)
}
@@ -1193,7 +1181,7 @@ impl Context {
/// ```
// REVIEW: Seems to be unassigned to anything
#[inline]
- pub fn metadata_string(&self, string: &str) -> MetadataValue {
+ pub fn metadata_string<'ctx>(&'ctx self, string: &str) -> MetadataValue<'ctx> {
self.context.metadata_string(string)
}
@@ -1305,7 +1293,7 @@ impl Context {
/// ```
// SubTypes: Should return ArrayValue>
#[inline]
- pub fn const_string(&self, string: &[u8], null_terminated: bool) -> ArrayValue {
+ pub fn const_string<'ctx>(&'ctx self, string: &[u8], null_terminated: bool) -> ArrayValue<'ctx> {
self.context.const_string(string, null_terminated)
}
@@ -1441,12 +1429,8 @@ impl<'ctx> ContextRef<'ctx> {
/// "=r,{rax},{rdi}".to_string(),
/// true,
/// false,
- /// #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))] None,
+ /// None,
/// #[cfg(not(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
/// feature = "llvm8-0",
/// feature = "llvm9-0",
/// feature = "llvm10-0",
@@ -1458,10 +1442,6 @@ impl<'ctx> ContextRef<'ctx> {
/// let params = &[context.i64_type().const_int(60, false).into(), context.i64_type().const_int(1, false).into()];
///
/// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
/// feature = "llvm8-0",
/// feature = "llvm9-0",
/// feature = "llvm10-0",
@@ -1476,7 +1456,7 @@ impl<'ctx> ContextRef<'ctx> {
/// builder.build_call(callable_value, params, "exit").unwrap();
/// }
///
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1"))]
/// builder.build_indirect_call(asm_fn, asm, params, "exit").unwrap();
///
/// builder.build_return(None).unwrap();
@@ -1489,14 +1469,8 @@ impl<'ctx> ContextRef<'ctx> {
constraints: String,
sideeffects: bool,
alignstack: bool,
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))] dialect: Option<
- InlineAsmDialect,
- >,
+ dialect: Option,
#[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -1511,13 +1485,8 @@ impl<'ctx> ContextRef<'ctx> {
constraints,
sideeffects,
alignstack,
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
dialect,
#[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -1685,7 +1654,6 @@ impl<'ctx> ContextRef<'ctx> {
/// assert_eq!(md_type.get_context(), context);
/// ```
#[inline]
- #[llvm_versions(6..)]
pub fn metadata_type(&self) -> MetadataType<'ctx> {
self.context.metadata_type()
}
@@ -1838,7 +1806,7 @@ impl<'ctx> ContextRef<'ctx> {
/// assert_eq!(ptr_type.get_address_space(), AddressSpace::default());
/// assert_eq!(ptr_type.get_context(), context);
/// ```
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
#[inline]
pub fn ptr_type(&self, address_space: AddressSpace) -> PointerType<'ctx> {
self.context.ptr_type(address_space)
diff --git a/src/debug_info.rs b/src/debug_info.rs
index 678db68060e..e33da152d24 100644
--- a/src/debug_info.rs
+++ b/src/debug_info.rs
@@ -108,7 +108,7 @@ use crate::values::{AsValueRef, BasicValueEnum, InstructionValue, MetadataValue,
use crate::AddressSpace;
use llvm_sys::core::LLVMMetadataAsValue;
-#[llvm_versions(8..)]
+
use llvm_sys::debuginfo::LLVMDIBuilderCreateTypedef;
pub use llvm_sys::debuginfo::LLVMDWARFTypeEncoding;
use llvm_sys::debuginfo::LLVMDebugMetadataVersion;
@@ -123,11 +123,25 @@ use llvm_sys::debuginfo::{
LLVMDIBuilderCreateMemberType, LLVMDIBuilderCreateNameSpace, LLVMDIBuilderCreateParameterVariable,
LLVMDIBuilderCreatePointerType, LLVMDIBuilderCreateReferenceType, LLVMDIBuilderCreateStructType,
LLVMDIBuilderCreateSubroutineType, LLVMDIBuilderCreateUnionType, LLVMDIBuilderFinalize,
- LLVMDIBuilderGetOrCreateSubrange, LLVMDIBuilderInsertDbgValueBefore, LLVMDIBuilderInsertDeclareAtEnd,
- LLVMDIBuilderInsertDeclareBefore, LLVMDILocationGetColumn, LLVMDILocationGetLine, LLVMDILocationGetScope,
+ LLVMDIBuilderGetOrCreateSubrange, LLVMDILocationGetColumn, LLVMDILocationGetLine, LLVMDILocationGetScope,
LLVMDITypeGetAlignInBits, LLVMDITypeGetOffsetInBits, LLVMDITypeGetSizeInBits,
};
-#[llvm_versions(8..)]
+
+#[llvm_versions(..19.1)]
+use llvm_sys::debuginfo::{
+ LLVMDIBuilderInsertDbgValueBefore, LLVMDIBuilderInsertDeclareAtEnd, LLVMDIBuilderInsertDeclareBefore,
+};
+
+#[llvm_versions(19.1..)]
+use llvm_sys::debuginfo::{
+ LLVMDIBuilderInsertDbgValueRecordBefore as LLVMDIBuilderInsertDbgValueBefore,
+ LLVMDIBuilderInsertDeclareRecordAtEnd as LLVMDIBuilderInsertDeclareAtEnd,
+ LLVMDIBuilderInsertDeclareRecordBefore as LLVMDIBuilderInsertDeclareBefore,
+};
+
+#[llvm_versions(19.1..)]
+use llvm_sys::prelude::LLVMValueRef;
+
use llvm_sys::debuginfo::{LLVMDIBuilderCreateConstantValueExpression, LLVMDIBuilderCreateGlobalVariableExpression};
use llvm_sys::prelude::{LLVMDIBuilderRef, LLVMMetadataRef};
use std::convert::TryInto;
@@ -157,7 +171,7 @@ pub struct DIScope<'ctx> {
_marker: PhantomData<&'ctx Context>,
}
-impl<'ctx> DIScope<'ctx> {
+impl DIScope<'_> {
/// Acquires the underlying raw pointer belonging to this `DIScope` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -195,7 +209,9 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sysroot: &str,
#[cfg(any(
@@ -206,7 +222,9 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sdk: &str,
) -> (Self, DICompileUnit<'ctx>) {
@@ -245,7 +263,9 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sysroot,
#[cfg(any(
@@ -256,7 +276,9 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sdk,
);
@@ -303,7 +325,9 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sysroot: &str,
#[cfg(any(
@@ -314,20 +338,14 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sdk: &str,
) -> DICompileUnit<'ctx> {
let metadata_ref = unsafe {
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0"
- ))]
+ #[cfg(any(feature = "llvm8-0", feature = "llvm9-0", feature = "llvm10-0"))]
{
LLVMDIBuilderCreateCompileUnit(
self.builder,
@@ -356,7 +374,9 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
{
LLVMDIBuilderCreateCompileUnit(
@@ -400,8 +420,8 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
/// * `ty` - Function type.
/// * `is_local_to_unit` - True if this function is not externally visible.
/// * `is_definition` - True if this is a function definition ("When isDefinition: false,
- /// subprograms describe a declaration in the type tree as opposed to a definition of a
- /// function").
+ /// subprograms describe a declaration in the type tree as opposed to a definition of a
+ /// function").
/// * `scope_line` - Set to the beginning of the scope this starts
/// * `flags` - E.g.: LLVMDIFlagLValueReference. These flags are used to emit dwarf attributes.
/// * `is_optimized` - True if optimization is ON.
@@ -511,18 +531,17 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
/// Create a primitive basic type. `encoding` is an unsigned int flag (`DW_ATE_*`
/// enum) defined by the chosen DWARF standard.
- #[llvm_versions(7..)]
pub fn create_basic_type(
&self,
name: &str,
size_in_bits: u64,
encoding: LLVMDWARFTypeEncoding,
- #[cfg(not(feature = "llvm7-0"))] flags: DIFlags,
- ) -> Result, &'static str> {
+ flags: DIFlags,
+ ) -> Result, crate::error::Error> {
if name.is_empty() {
// Also, LLVM returns the same type if you ask for the same
// (name, size_in_bits, encoding).
- return Err("basic types must have names");
+ return Err(crate::error::Error::EmptyNameError);
}
let metadata_ref = unsafe {
LLVMDIBuilderCreateBasicType(
@@ -531,7 +550,6 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
name.len(),
size_in_bits,
encoding,
- #[cfg(not(feature = "llvm7-0"))]
flags,
)
};
@@ -542,7 +560,6 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
}
/// Create a typedef (alias) of `ditype`
- #[llvm_versions(8..)]
pub fn create_typedef(
&self,
ditype: DIType<'ctx>,
@@ -791,7 +808,6 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
}
}
- #[llvm_versions(8..)]
pub fn create_global_variable_expression(
&self,
scope: DIScope<'ctx>,
@@ -830,7 +846,6 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
}
}
- #[llvm_versions(8..)]
pub fn create_constant_expression(&self, value: i64) -> DIExpression<'ctx> {
let metadata_ref = unsafe { LLVMDIBuilderCreateConstantValueExpression(self.builder, value as _) };
@@ -940,7 +955,18 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
)
};
- unsafe { InstructionValue::new(value_ref) }
+ #[cfg(any(feature = "llvm19-1", feature = "llvm20-1"))]
+ {
+ // In LLVM 19+, the insert... functions return a DbgRecord, not a Value.
+ // We need to cast it to a ValueRef to create an InstructionValue.
+ // This is unsafe, but it's the only way to do it.
+ unsafe { InstructionValue::new(value_ref as LLVMValueRef) }
+ }
+
+ #[cfg(not(any(feature = "llvm19-1", feature = "llvm20-1")))]
+ {
+ unsafe { InstructionValue::new(value_ref) }
+ }
}
/// Insert a variable declaration (`llvm.dbg.declare` intrinsic) at the end of `block`
@@ -963,7 +989,18 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
)
};
- unsafe { InstructionValue::new(value_ref) }
+ #[cfg(any(feature = "llvm19-1", feature = "llvm20-1"))]
+ {
+ // In LLVM 19+, the insert... functions return a DbgRecord, not a Value.
+ // We need to cast it to a ValueRef to create an InstructionValue.
+ // This is unsafe, but it's the only way to do it.
+ unsafe { InstructionValue::new(value_ref as LLVMValueRef) }
+ }
+
+ #[cfg(not(any(feature = "llvm19-1", feature = "llvm20-1")))]
+ {
+ unsafe { InstructionValue::new(value_ref) }
+ }
}
/// Create an expression
@@ -1001,7 +1038,18 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
)
};
- unsafe { InstructionValue::new(value_ref) }
+ #[cfg(any(feature = "llvm19-1", feature = "llvm20-1"))]
+ {
+ // In LLVM 19+, the insert... functions return a DbgRecord, not a Value.
+ // We need to cast it to a ValueRef to create an InstructionValue.
+ // This is unsafe, but it's the only way to do it.
+ unsafe { InstructionValue::new(value_ref as LLVMValueRef) }
+ }
+
+ #[cfg(not(any(feature = "llvm19-1", feature = "llvm20-1")))]
+ {
+ unsafe { InstructionValue::new(value_ref) }
+ }
}
/// Construct a placeholders derived type to be used when building debug info with circular references.
@@ -1037,7 +1085,7 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
}
}
-impl<'ctx> Drop for DebugInfoBuilder<'ctx> {
+impl Drop for DebugInfoBuilder<'_> {
fn drop(&mut self) {
self.finalize();
unsafe { LLVMDisposeDIBuilder(self.builder) }
@@ -1060,7 +1108,7 @@ impl<'ctx> AsDIScope<'ctx> for DIFile<'ctx> {
}
}
-impl<'ctx> DIFile<'ctx> {
+impl DIFile<'_> {
/// Acquires the underlying raw pointer belonging to this `DIFile` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -1102,7 +1150,7 @@ pub struct DINamespace<'ctx> {
_marker: PhantomData<&'ctx Context>,
}
-impl<'ctx> DINamespace<'ctx> {
+impl DINamespace<'_> {
/// Acquires the underlying raw pointer belonging to this `DINamespace` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -1134,7 +1182,7 @@ impl<'ctx> AsDIScope<'ctx> for DISubprogram<'ctx> {
}
}
-impl<'ctx> DISubprogram<'ctx> {
+impl DISubprogram<'_> {
/// Acquires the underlying raw pointer belonging to this `DISubprogram` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -1148,7 +1196,7 @@ pub struct DIType<'ctx> {
_marker: PhantomData<&'ctx Context>,
}
-impl<'ctx> DIType<'ctx> {
+impl DIType<'_> {
pub fn get_size_in_bits(&self) -> u64 {
unsafe { LLVMDITypeGetSizeInBits(self.metadata_ref) }
}
@@ -1192,7 +1240,7 @@ impl<'ctx> DIDerivedType<'ctx> {
}
}
-impl<'ctx> DIDerivedType<'ctx> {
+impl DIDerivedType<'_> {
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
}
@@ -1289,7 +1337,7 @@ impl<'ctx> AsDIScope<'ctx> for DILexicalBlock<'ctx> {
}
}
-impl<'ctx> DILexicalBlock<'ctx> {
+impl DILexicalBlock<'_> {
/// Acquires the underlying raw pointer belonging to this `DILexicalBlock` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -1339,7 +1387,7 @@ pub struct DILocalVariable<'ctx> {
_marker: PhantomData<&'ctx Context>,
}
-impl<'ctx> DILocalVariable<'ctx> {
+impl DILocalVariable<'_> {
/// Acquires the underlying raw pointer belonging to this `DILocalVariable` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -1363,14 +1411,18 @@ impl<'ctx> DIGlobalVariableExpression<'ctx> {
}
}
-/// https://llvm.org/docs/LangRef.html#diexpression
+/// Specialized metadata node that contains a DWARF-like expression.
+///
+/// # Remarks
+///
+/// See also the [LLVM language reference](https://llvm.org/docs/LangRef.html#diexpression).
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DIExpression<'ctx> {
pub(crate) metadata_ref: LLVMMetadataRef,
_marker: PhantomData<&'ctx Context>,
}
-impl<'ctx> DIExpression<'ctx> {
+impl DIExpression<'_> {
/// Acquires the underlying raw pointer belonging to this `DIExpression` type.
pub fn as_mut_ptr(&self) -> LLVMMetadataRef {
self.metadata_ref
@@ -1389,7 +1441,7 @@ mod flags {
const PUBLIC: Self;
const FWD_DECL: Self;
const APPLE_BLOCK: Self;
- //#[llvm_versions(7..=9)]
+ //#[llvm_versions(8..=9)]
//const BLOCK_BYREF_STRUCT: Self;
const VIRTUAL: Self;
const ARTIFICIAL: Self;
@@ -1408,24 +1460,22 @@ mod flags {
const INTRODUCED_VIRTUAL: Self;
const BIT_FIELD: Self;
const NO_RETURN: Self;
- //#[llvm_versions(7..=8)]
+ //#[llvm_versions(8..=8)]
//const MAIN_SUBPROGRAM: Self;
const TYPE_PASS_BY_VALUE: Self;
const TYPE_PASS_BY_REFERENCE: Self;
- //#[llvm_versions(7)]
- //const FIXED_ENUM: Self;
- //#[llvm_versions(8..)]
+ //
//const ENUM_CLASS: Self;
const THUNK: Self;
- //#[llvm_versions(7..=8)]
+ //#[llvm_versions(8..=8)]
//const TRIVIAL: Self;
//#[llvm_versions(9..)]
//const NON_TRIVIAL: Self;
//#[llvm_versions(10)]
//const RESERVED_BIT4: Self;
- //#[llvm_versions(8..)]
+ //
//const BIGE_NDIAN: Self;
- //#[llvm_versions(8..)]
+ //
//const LITTLE_ENDIAN: Self;
const INDIRECT_VIRTUAL_BASE: Self;
}
@@ -1436,7 +1486,7 @@ mod flags {
const PUBLIC: DIFlags = llvm_sys::debuginfo::LLVMDIFlagPublic;
const FWD_DECL: DIFlags = llvm_sys::debuginfo::LLVMDIFlagFwdDecl;
const APPLE_BLOCK: DIFlags = llvm_sys::debuginfo::LLVMDIFlagAppleBlock;
- //#[llvm_versions(7..=9)]
+ //#[llvm_versions(8..=9)]
//const BLOCK_BYREF_STRUCT: DIFlags = llvm_sys::debuginfo::LLVMDIFlagBlockByrefStruct;
const VIRTUAL: DIFlags = llvm_sys::debuginfo::LLVMDIFlagVirtual;
const ARTIFICIAL: DIFlags = llvm_sys::debuginfo::LLVMDIFlagArtificial;
@@ -1455,24 +1505,22 @@ mod flags {
const INTRODUCED_VIRTUAL: DIFlags = llvm_sys::debuginfo::LLVMDIFlagIntroducedVirtual;
const BIT_FIELD: DIFlags = llvm_sys::debuginfo::LLVMDIFlagBitField;
const NO_RETURN: DIFlags = llvm_sys::debuginfo::LLVMDIFlagNoReturn;
- //#[llvm_versions(7..=8)]
+ //#[llvm_versions(8..=8)]
//const MAIN_SUBPROGRAM: DIFlags = llvm_sys::debuginfo::LLVMDIFlagMainSubprogram;
const TYPE_PASS_BY_VALUE: DIFlags = llvm_sys::debuginfo::LLVMDIFlagTypePassByValue;
const TYPE_PASS_BY_REFERENCE: DIFlags = llvm_sys::debuginfo::LLVMDIFlagTypePassByReference;
- //#[llvm_versions(7)]
- //const FIXED_ENUM: DIFlags = llvm_sys::debuginfo::LLVMDIFlagFixedEnum;
- //#[llvm_versions(8..)]
+ //
//const ENUM_CLASS: DIFlags = llvm_sys::debuginfo::LLVMDIFlagEnumClass;
const THUNK: DIFlags = llvm_sys::debuginfo::LLVMDIFlagThunk;
- //#[llvm_versions(7..=8)]
+ //#[llvm_versions(8..=8)]
//const TRIVIAL: DIFlags = llvm_sys::debuginfo::LLVMDIFlagTrivial;
//#[llvm_versions(9..)]
//const NON_TRIVIAL: DIFlags = llvm_sys::debuginfo::LLVMDIFlagNonTrivial;
//#[llvm_versions(10)]
//const RESERVED_BIT4: DIFlags = llvm_sys::debuginfo::LLVMDIFlagReservedBit4;
- //#[llvm_versions(8..)]
+ //
//const BIG_ENDIAN: DIFlags = llvm_sys::debuginfo::LLVMDIFlagBigEndian;
- //#[llvm_versions(8..)]
+ //
//const LITTLE_ENDIAN: DIFlags = llvm_sys::debuginfo::LLVMDIFlagLittleEndian;
const INDIRECT_VIRTUAL_BASE: DIFlags = llvm_sys::debuginfo::LLVMDIFlagIndirectVirtualBase;
}
@@ -1603,5 +1651,57 @@ mod flags {
#[llvm_versions(17..)]
#[llvm_variant(LLVMDWARFSourceLanguageMojo)]
Mojo,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageHIP)]
+ Hip,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageAssembly)]
+ Assembly,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageC_sharp)]
+ Csharp,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageGLSL)]
+ Glsl,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageGLSL_ES)]
+ GlslEs,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageHLSL)]
+ Hlsl,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageOpenCL_CPP)]
+ OpenClCpp,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageCPP_for_OpenCL)]
+ CppForOpenCl,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageSYCL)]
+ Sycl,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageRuby)]
+ Ruby,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageMove)]
+ Move,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageHylo)]
+ Hylo,
+
+ #[llvm_versions(20..)]
+ #[llvm_variant(LLVMDWARFSourceLanguageMetal)]
+ Metal,
}
}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 00000000000..3e6e10831c3
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,30 @@
+/// Errors for operations involving alignment.
+#[derive(Debug, thiserror::Error, PartialEq, Eq)]
+pub enum AlignmentError {
+ #[error("{0} is not a power of two and cannot be used for alignment")]
+ NonPowerOfTwo(u32),
+ #[error("The src_align_bytes argument was not a power of two.")]
+ SrcNonPowerOfTwo(u32),
+ #[error("The dest_align_bytes argument was not a power of two.")]
+ DestNonPowerOfTwo(u32),
+ #[error(
+ "Type is unsized and cannot be aligned. \
+ Suggestion: Align memory manually."
+ )]
+ Unsized,
+ #[error("Value is not an alloca, load, or store instruction.")]
+ UnalignedInstruction,
+}
+
+/// The top-level Error type for the inkwell crate.
+#[derive(Debug, thiserror::Error, PartialEq, Eq)]
+pub enum Error {
+ #[error("Builder Error: {0}")]
+ BuilderError(#[from] crate::builder::BuilderError),
+ #[error("InstructionValue Error: {0}")]
+ InstructionValueError(#[from] crate::values::InstructionValueError),
+ #[error("Basic types must have names.")]
+ EmptyNameError,
+ #[error("Metadata is expected to be a node.")]
+ GlobalMetadataError,
+}
diff --git a/src/execution_engine.rs b/src/execution_engine.rs
index 1f032782795..0de13a79ef3 100644
--- a/src/execution_engine.rs
+++ b/src/execution_engine.rs
@@ -332,9 +332,9 @@ impl<'ctx> ExecutionEngine<'ctx> {
/// It is recommended to use `get_function` instead of this method when intending to call the function
/// pointer so that you don't have to do error-prone transmutes yourself.
pub fn get_function_address(&self, fn_name: &str) -> Result {
- // LLVMGetFunctionAddress segfaults in llvm 5.0 -> 8.0 when fn_name doesn't exist. This is a workaround
+ // LLVMGetFunctionAddress segfaults in llvm 8.0 when fn_name doesn't exist. This is a workaround
// to see if it exists and avoid the segfault when it doesn't
- #[cfg(any(feature = "llvm5-0", feature = "llvm6-0", feature = "llvm7-0", feature = "llvm8-0"))]
+ #[cfg(feature = "llvm8-0")]
self.get_function_value(fn_name)?;
let c_string = to_c_str(fn_name);
@@ -487,7 +487,7 @@ pub struct JitFunction<'ctx, F> {
inner: F,
}
-impl<'ctx, F: Copy> JitFunction<'ctx, F> {
+impl JitFunction<'_, F> {
/// Returns the raw function pointer, consuming self in the process.
/// This function is unsafe because the function pointer may dangle
/// if the ExecutionEngine it came from is dropped. The caller is
diff --git a/src/intrinsics.rs b/src/intrinsics.rs
index 93dfdd1abca..0fa4c06398d 100644
--- a/src/intrinsics.rs
+++ b/src/intrinsics.rs
@@ -1,4 +1,3 @@
-#[llvm_versions(9..)]
use llvm_sys::core::{LLVMGetIntrinsicDeclaration, LLVMIntrinsicIsOverloaded, LLVMLookupIntrinsicID};
use llvm_sys::prelude::LLVMTypeRef;
@@ -14,7 +13,6 @@ pub struct Intrinsic {
/// A wrapper around LLVM intrinsic id
///
/// To call it you would need to create a declaration inside a module using [`Self::get_declaration()`].
-#[llvm_versions(9..)]
impl Intrinsic {
/// Create an Intrinsic object from raw LLVM intrinsic id
///
diff --git a/src/lib.rs b/src/lib.rs
index 9917f35920e..3788bf4a86f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,16 +23,17 @@ pub mod attributes;
pub mod basic_block;
pub mod builder;
#[deny(missing_docs)]
-#[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
pub mod comdat;
#[deny(missing_docs)]
pub mod context;
pub mod data_layout;
-#[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
pub mod debug_info;
+pub mod error;
pub mod execution_engine;
+#[cfg(not(feature = "llvm8-0"))]
pub mod intrinsics;
pub mod memory_buffer;
+pub mod memory_manager;
#[deny(missing_docs)]
pub mod module;
pub mod object_file;
@@ -58,16 +59,12 @@ pub extern crate llvm_sys_150 as llvm_sys;
pub extern crate llvm_sys_160 as llvm_sys;
#[cfg(feature = "llvm17-0")]
pub extern crate llvm_sys_170 as llvm_sys;
-#[cfg(feature = "llvm18-0")]
-pub extern crate llvm_sys_180 as llvm_sys;
-#[cfg(feature = "llvm4-0")]
-pub extern crate llvm_sys_40 as llvm_sys;
-#[cfg(feature = "llvm5-0")]
-pub extern crate llvm_sys_50 as llvm_sys;
-#[cfg(feature = "llvm6-0")]
-pub extern crate llvm_sys_60 as llvm_sys;
-#[cfg(feature = "llvm7-0")]
-pub extern crate llvm_sys_70 as llvm_sys;
+#[cfg(feature = "llvm18-1")]
+pub extern crate llvm_sys_181 as llvm_sys;
+#[cfg(feature = "llvm19-1")]
+pub extern crate llvm_sys_191 as llvm_sys;
+#[cfg(feature = "llvm20-1")]
+pub extern crate llvm_sys_201 as llvm_sys;
#[cfg(feature = "llvm8-0")]
pub extern crate llvm_sys_80 as llvm_sys;
#[cfg(feature = "llvm9-0")]
@@ -79,9 +76,10 @@ use llvm_sys::{
LLVMThreadLocalMode, LLVMVisibility,
};
-#[llvm_versions(7..)]
use llvm_sys::LLVMInlineAsmDialect;
+pub use either::Either;
+pub use error::Error;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
@@ -116,10 +114,6 @@ macro_rules! assert_unique_used_features {
}
assert_unique_used_features! {
- "llvm4-0",
- "llvm5-0",
- "llvm6-0",
- "llvm7-0",
"llvm8-0",
"llvm9-0",
"llvm10-0",
@@ -130,24 +124,43 @@ assert_unique_used_features! {
"llvm15-0",
"llvm16-0",
"llvm17-0",
- "llvm18-0"
+ "llvm18-1",
+ "llvm19-1",
+ "llvm20-1"
}
+#[cfg(all(
+ any(
+ feature = "llvm8-0",
+ feature = "llvm9-0",
+ feature = "llvm10-0",
+ feature = "llvm11-0",
+ feature = "llvm12-0",
+ feature = "llvm13-0",
+ feature = "llvm14-0"
+ ),
+ not(feature = "typed-pointers")
+))]
+compile_error!("Opaque pointers are not supported prior to LLVM version 15.0.");
+
+#[cfg(all(any(feature = "llvm17-0", feature = "llvm18-1"), feature = "typed-pointers"))]
+compile_error!("Typed pointers are not supported starting from LLVM version 17.0.");
+
/// Defines the address space in which a global will be inserted.
///
-/// The default address space is zero. An address space can always be created from a `u16`:
+/// The default address space is number zero. An address space can always be created from a [`u16`]:
/// ```no_run
/// inkwell::AddressSpace::from(1u16);
/// ```
///
-/// An Address space is a 24-bit number. To convert from a u32, use the `TryFrom` instance
+/// An address space is a 24-bit number. To convert from a [`u32`], use the [`TryFrom`] implementation:
///
/// ```no_run
/// inkwell::AddressSpace::try_from(42u32).expect("fits in 24-bit unsigned int");
/// ```
///
/// # Remarks
-/// See also: https://llvm.org/doxygen/NVPTXBaseInfo_8h_source.html
+/// See also:
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
pub struct AddressSpace(u32);
@@ -376,12 +389,29 @@ pub enum AtomicRMWBinOp {
#[llvm_versions(15..)]
#[llvm_variant(LLVMAtomicRMWBinOpFMin)]
FMin,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMAtomicRMWBinOpUIncWrap)]
+ UIncWrap,
+
+ #[llvm_versions(19.1..)]
+ #[llvm_variant(LLVMAtomicRMWBinOpUDecWrap)]
+ UDecWrap,
+
+ #[llvm_versions(20..)]
+ #[llvm_variant(LLVMAtomicRMWBinOpUSubCond)]
+ USubCond,
+
+ #[llvm_versions(20..)]
+ #[llvm_variant(LLVMAtomicRMWBinOpUSubSat)]
+ USubSat,
}
-/// Defines the optimization level used to compile a `Module`.
+/// Defines the optimization level used to compile a [`Module`](crate::module::Module).
///
/// # Remarks
-/// See also: https://llvm.org/doxygen/CodeGen_8h_source.html
+///
+/// See the C++ API documentation: [`llvm::CodeGenOpt`](https://llvm.org/doxygen/namespacellvm_1_1CodeGenOpt.html).
#[repr(u32)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -479,7 +509,6 @@ impl Default for DLLStorageClass {
}
}
-#[llvm_versions(7..)]
#[llvm_enum(LLVMInlineAsmDialect)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
diff --git a/src/memory_manager.rs b/src/memory_manager.rs
new file mode 100644
index 00000000000..8634f946c9a
--- /dev/null
+++ b/src/memory_manager.rs
@@ -0,0 +1,180 @@
+use llvm_sys::prelude::LLVMBool;
+
+/// A trait for user-defined memory management in MCJIT.
+///
+/// Implementors can override how LLVM's MCJIT engine allocates memory for code
+/// and data sections. This is sometimes needed for:
+/// - custom allocators,
+/// - sandboxed or restricted environments,
+/// - capturing stack map sections (e.g., for garbage collection),
+/// - or other specialized JIT memory management requirements.
+///
+/// # StackMap and GC Integration
+///
+/// By examining the `section_name` argument in [`McjitMemoryManager::allocate_data_section`],
+/// you can detect sections such as `.llvm_stackmaps` (on ELF) or `__llvm_stackmaps`
+/// (on Mach-O). Recording the location of these sections may be useful for
+/// custom garbage collectors. For more information, refer to the [LLVM
+/// StackMaps documentation](https://llvm.org/docs/StackMaps.html#stack-map-section).
+///
+/// Typically, on Darwin (Mach-O), the stack map section name is `__llvm_stackmaps`,
+/// and on Linux (ELF), it is `.llvm_stackmaps`.
+pub trait McjitMemoryManager: std::fmt::Debug {
+ /// Allocates a block of memory for a code section.
+ ///
+ /// # Parameters
+ ///
+ /// * `size` - The size in bytes for the code section.
+ /// * `alignment` - The required alignment in bytes.
+ /// * `section_id` - A numeric ID that LLVM uses to identify this section.
+ /// * `section_name` - A name for this section, if provided by LLVM.
+ ///
+ /// # Returns
+ ///
+ /// Returns a pointer to the allocated memory. Implementors must ensure it is
+ /// at least `size` bytes long and meets `alignment` requirements.
+ fn allocate_code_section(
+ &mut self,
+ size: libc::uintptr_t,
+ alignment: libc::c_uint,
+ section_id: libc::c_uint,
+ section_name: &str,
+ ) -> *mut u8;
+
+ /// Allocates a block of memory for a data section.
+ ///
+ /// # Parameters
+ ///
+ /// * `size` - The size in bytes for the data section.
+ /// * `alignment` - The required alignment in bytes.
+ /// * `section_id` - A numeric ID that LLVM uses to identify this section.
+ /// * `section_name` - A name for this section, if provided by LLVM.
+ /// * `is_read_only` - Whether this data section should be read-only.
+ ///
+ /// # Returns
+ ///
+ /// Returns a pointer to the allocated memory. Implementors must ensure it is
+ /// at least `size` bytes long and meets `alignment` requirements.
+ fn allocate_data_section(
+ &mut self,
+ size: libc::uintptr_t,
+ alignment: libc::c_uint,
+ section_id: libc::c_uint,
+ section_name: &str,
+ is_read_only: bool,
+ ) -> *mut u8;
+
+ /// Finalizes memory permissions for all allocated sections.
+ ///
+ /// This is called once all sections have been allocated. Implementors can set
+ /// permissions such as making code sections executable or data sections
+ /// read-only.
+ ///
+ /// # Errors
+ ///
+ /// If any error occurs (for example, failing to set page permissions),
+ /// return an `Err(String)`. This error is reported back to LLVM as a C string.
+ fn finalize_memory(&mut self) -> Result<(), String>;
+
+ /// Cleans up or deallocates resources before the memory manager is destroyed.
+ ///
+ /// This is called when LLVM has finished using the memory manager. Any
+ /// additional allocations or references should be released here if needed.
+ fn destroy(&mut self);
+}
+
+/// Holds a boxed `McjitMemoryManager` and passes it to LLVM as an opaque pointer.
+///
+/// LLVM calls into the adapter using the extern "C" function pointers defined below.
+#[derive(Debug)]
+pub struct MemoryManagerAdapter {
+ pub memory_manager: Box,
+}
+
+// ------ Extern "C" Adapters ------
+
+/// Adapter for `allocate_code_section`.
+///
+/// Called by LLVM with a raw pointer (`opaque`). Casts back to `MemoryManagerAdapter`
+/// and delegates to `allocate_code_section`.
+pub(crate) extern "C" fn allocate_code_section_adapter(
+ opaque: *mut libc::c_void,
+ size: libc::uintptr_t,
+ alignment: libc::c_uint,
+ section_id: libc::c_uint,
+ section_name: *const libc::c_char,
+) -> *mut u8 {
+ let adapter = unsafe { &mut *(opaque as *mut MemoryManagerAdapter) };
+ let sname = unsafe { c_str_to_str(section_name) };
+ adapter
+ .memory_manager
+ .allocate_code_section(size, alignment, section_id, sname)
+}
+
+/// Adapter for `allocate_data_section`.
+///
+/// Note that `LLVMBool` is `0` for false, and `1` for true. We check `!= 0` to
+/// interpret it as a bool.
+pub(crate) extern "C" fn allocate_data_section_adapter(
+ opaque: *mut libc::c_void,
+ size: libc::uintptr_t,
+ alignment: libc::c_uint,
+ section_id: libc::c_uint,
+ section_name: *const libc::c_char,
+ is_read_only: LLVMBool,
+) -> *mut u8 {
+ let adapter = unsafe { &mut *(opaque as *mut MemoryManagerAdapter) };
+ let sname = unsafe { c_str_to_str(section_name) };
+ adapter
+ .memory_manager
+ .allocate_data_section(size, alignment, section_id, sname, is_read_only != 0)
+}
+
+/// Adapter for `finalize_memory`.
+///
+/// If an error is returned, the message is converted into a C string and set in `err_msg_out`.
+pub(crate) extern "C" fn finalize_memory_adapter(
+ opaque: *mut libc::c_void,
+ err_msg_out: *mut *mut libc::c_char,
+) -> libc::c_int {
+ let adapter = unsafe { &mut *(opaque as *mut MemoryManagerAdapter) };
+ match adapter.memory_manager.finalize_memory() {
+ Ok(()) => 0,
+ Err(e) => {
+ let cstring = std::ffi::CString::new(e).unwrap_or_default();
+ unsafe {
+ *err_msg_out = cstring.into_raw();
+ }
+ 1
+ },
+ }
+}
+
+/// Adapter for `destroy`.
+///
+/// Called when LLVM is done with the memory manager. Calls `destroy` and drops
+/// the adapter to free resources.
+pub(crate) extern "C" fn destroy_adapter(opaque: *mut libc::c_void) {
+ // Re-box to drop the adapter and its contents.
+ // SAFETY: `opaque` must have been allocated by Box.
+ let mut adapter = unsafe { Box::from_raw(opaque as *mut MemoryManagerAdapter) };
+
+ // Clean up user-defined resources
+ adapter.memory_manager.destroy();
+
+ // Dropping `adapter` automatically frees the memory
+}
+
+/// Converts a raw C string pointer to a Rust `&str`.
+///
+/// # Safety
+///
+/// The caller must ensure `ptr` points to a valid, null-terminated UTF-8 string.
+/// If the string is invalid UTF-8 or `ptr` is null, an empty string is returned.
+unsafe fn c_str_to_str<'a>(ptr: *const libc::c_char) -> &'a str {
+ if ptr.is_null() {
+ ""
+ } else {
+ unsafe { std::ffi::CStr::from_ptr(ptr) }.to_str().unwrap_or("")
+ }
+}
diff --git a/src/module.rs b/src/module.rs
index 14c79a5cffe..ed096ecfa8f 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -4,32 +4,33 @@ use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyModule};
#[allow(deprecated)]
use llvm_sys::bit_reader::LLVMParseBitcodeInContext;
use llvm_sys::bit_writer::{LLVMWriteBitcodeToFile, LLVMWriteBitcodeToMemoryBuffer};
-#[llvm_versions(..=14)]
+#[llvm_versions(..=11)]
use llvm_sys::core::LLVMGetTypeByName;
-
use llvm_sys::core::{
LLVMAddFunction, LLVMAddGlobal, LLVMAddGlobalInAddressSpace, LLVMAddNamedMetadataOperand, LLVMCloneModule,
- LLVMDisposeModule, LLVMDumpModule, LLVMGetFirstFunction, LLVMGetFirstGlobal, LLVMGetLastFunction,
- LLVMGetLastGlobal, LLVMGetModuleContext, LLVMGetModuleIdentifier, LLVMGetNamedFunction, LLVMGetNamedGlobal,
- LLVMGetNamedMetadataNumOperands, LLVMGetNamedMetadataOperands, LLVMGetTarget, LLVMPrintModuleToFile,
- LLVMPrintModuleToString, LLVMSetDataLayout, LLVMSetModuleIdentifier, LLVMSetTarget, LLVMDisposeMessage
+ LLVMDisposeMessage, LLVMDisposeModule, LLVMDumpModule, LLVMGetFirstFunction, LLVMGetFirstGlobal,
+ LLVMGetLastFunction, LLVMGetLastGlobal, LLVMGetModuleContext, LLVMGetModuleIdentifier, LLVMGetNamedFunction,
+ LLVMGetNamedGlobal, LLVMGetNamedMetadataNumOperands, LLVMGetNamedMetadataOperands, LLVMGetTarget,
+ LLVMPrintModuleToFile, LLVMPrintModuleToString, LLVMSetDataLayout, LLVMSetModuleIdentifier,
+ LLVMSetModuleInlineAsm2, LLVMSetTarget,
};
-#[llvm_versions(7..)]
use llvm_sys::core::{LLVMAddModuleFlag, LLVMGetModuleFlag};
+use llvm_sys::debuginfo::{LLVMGetModuleDebugMetadataVersion, LLVMStripModuleDebugInfo};
#[llvm_versions(13..)]
use llvm_sys::error::LLVMGetErrorMessage;
use llvm_sys::execution_engine::{
LLVMCreateExecutionEngineForModule, LLVMCreateInterpreterForModule, LLVMCreateJITCompilerForModule,
+ LLVMCreateSimpleMCJITMemoryManager,
};
use llvm_sys::prelude::{LLVMModuleRef, LLVMValueRef};
#[llvm_versions(13..)]
use llvm_sys::transforms::pass_builder::LLVMRunPasses;
use llvm_sys::LLVMLinkage;
-#[llvm_versions(7..)]
+
use llvm_sys::LLVMModuleFlagBehavior;
use std::cell::{Cell, Ref, RefCell};
-use std::ffi::CStr;
+use std::ffi::{c_void, CStr};
use std::fs::File;
use std::marker::PhantomData;
use std::mem::{forget, MaybeUninit};
@@ -37,22 +38,25 @@ use std::path::Path;
use std::ptr;
use std::rc::Rc;
-#[llvm_versions(7..)]
use crate::comdat::Comdat;
use crate::context::{AsContextRef, Context, ContextRef};
use crate::data_layout::DataLayout;
-#[llvm_versions(7..)]
+
use crate::debug_info::{DICompileUnit, DWARFEmissionKind, DWARFSourceLanguage, DebugInfoBuilder};
use crate::execution_engine::ExecutionEngine;
use crate::memory_buffer::MemoryBuffer;
+use crate::memory_manager::{
+ allocate_code_section_adapter, allocate_data_section_adapter, destroy_adapter, finalize_memory_adapter,
+ McjitMemoryManager, MemoryManagerAdapter,
+};
#[llvm_versions(13..)]
use crate::passes::PassBuilderOptions;
use crate::support::{to_c_str, LLVMString};
#[llvm_versions(13..)]
use crate::targets::TargetMachine;
-use crate::targets::{InitializationConfig, Target, TargetTriple};
+use crate::targets::{CodeModel, InitializationConfig, Target, TargetTriple};
use crate::types::{AsTypeRef, BasicType, FunctionType, StructType};
-#[llvm_versions(7..)]
+
use crate::values::BasicValue;
use crate::values::{AsValueRef, FunctionValue, GlobalValue, MetadataValue};
use crate::{AddressSpace, OptimizationLevel};
@@ -609,6 +613,134 @@ impl<'ctx> Module<'ctx> {
Ok(execution_engine)
}
+ /// Creates an MCJIT `ExecutionEngine` for this `Module` using a custom memory manager.
+ ///
+ /// # Parameters
+ ///
+ /// * `memory_manager` - Specifies how LLVM allocates and finalizes code and data sections.
+ /// Implement the [`McjitMemoryManager`] trait to customize these operations.
+ /// * `opt_level` - Sets the desired optimization level (e.g. `None`, `Less`, `Default`, `Aggressive`).
+ /// Higher levels generally produce faster code at the expense of longer compilation times.
+ /// * `code_model` - Determines how code addresses are represented. Common values include
+ /// `CodeModel::Default` or `CodeModel::JITDefault`. This impacts the generated machine code layout.
+ /// * `no_frame_pointer_elim` - If true, frame pointer elimination is disabled. This may assist
+ /// with certain debugging or profiling tasks but can incur a performance cost.
+ /// * `enable_fast_isel` - If true, uses a faster instruction selector where possible. This can
+ /// improve compilation speed, though it may produce less optimized code in some cases.
+ ///
+ /// # Returns
+ ///
+ /// Returns a newly created [`ExecutionEngine`] for MCJIT on success. Returns an error if:
+ /// - The native target fails to initialize,
+ /// - The `Module` is already owned by another `ExecutionEngine`,
+ /// - Or MCJIT fails to create the engine (in which case an error string is returned from LLVM).
+ ///
+ /// # Notes
+ ///
+ /// Using a custom memory manager can help intercept or manage allocations for specific
+ /// sections (for example, capturing `.llvm_stackmaps` or applying custom permissions).
+ /// For details, refer to the [`McjitMemoryManager`] documentation.
+ ///
+ /// # Safety
+ ///
+ /// The returned [`ExecutionEngine`] takes ownership of the memory manager. Do not move
+ /// or free the `memory_manager` after calling this method. When the `ExecutionEngine`
+ /// is dropped, LLVM will destroy the memory manager by calling
+ /// [`McjitMemoryManager::destroy()`] and freeing its adapter.
+ pub fn create_mcjit_execution_engine_with_memory_manager(
+ &self,
+ memory_manager: impl McjitMemoryManager + 'static,
+ opt_level: OptimizationLevel,
+ code_model: CodeModel,
+ no_frame_pointer_elim: bool,
+ enable_fast_isel: bool,
+ ) -> Result, LLVMString> {
+ use std::mem::MaybeUninit;
+ // ...
+
+ // 1) Initialize the native target
+ Target::initialize_native(&InitializationConfig::default()).map_err(|mut err_string| {
+ err_string.push('\0');
+ LLVMString::create_from_str(&err_string)
+ })?;
+
+ // Check if the module is already owned by an ExecutionEngine
+ if self.owned_by_ee.borrow().is_some() {
+ let string = "This module is already owned by an ExecutionEngine.\0";
+ return Err(LLVMString::create_from_str(string));
+ }
+
+ // 2) Box the memory_manager into a MemoryManagerAdapter
+ let adapter = MemoryManagerAdapter {
+ memory_manager: Box::new(memory_manager),
+ };
+ let adapter_box = Box::new(adapter);
+ // Convert the Box into a raw pointer for LLVM.
+ // In `destroy_adapter`, we use `Box::from_raw` to safely reclaim ownership.
+ let opaque = Box::into_raw(adapter_box) as *mut c_void;
+
+ // 3) Create the LLVMMCJITMemoryManager using the custom callbacks
+ let mmgr = unsafe {
+ LLVMCreateSimpleMCJITMemoryManager(
+ opaque,
+ allocate_code_section_adapter,
+ allocate_data_section_adapter,
+ finalize_memory_adapter,
+ Some(destroy_adapter),
+ )
+ };
+ if mmgr.is_null() {
+ let msg = "Failed to create SimpleMCJITMemoryManager.\0";
+ return Err(LLVMString::create_from_str(msg));
+ }
+
+ // 4) Build LLVMMCJITCompilerOptions
+ let mut options_uninit = MaybeUninit::::zeroed();
+ unsafe {
+ // Ensure defaults are initialized
+ llvm_sys::execution_engine::LLVMInitializeMCJITCompilerOptions(
+ options_uninit.as_mut_ptr(),
+ std::mem::size_of::(),
+ );
+ }
+ let mut options = unsafe { options_uninit.assume_init() };
+
+ // Override fields
+ options.OptLevel = opt_level as u32;
+ options.CodeModel = code_model.into();
+ options.NoFramePointerElim = no_frame_pointer_elim as i32;
+ options.EnableFastISel = enable_fast_isel as i32;
+ options.MCJMM = mmgr;
+
+ // 5) Create MCJIT
+ let mut execution_engine = MaybeUninit::uninit();
+ let mut err_string = MaybeUninit::uninit();
+ let code = unsafe {
+ llvm_sys::execution_engine::LLVMCreateMCJITCompilerForModule(
+ execution_engine.as_mut_ptr(),
+ self.module.get(),
+ &mut options,
+ std::mem::size_of::(),
+ err_string.as_mut_ptr(),
+ )
+ };
+
+ // If creation fails, extract the error string
+ if code == 1 {
+ unsafe {
+ return Err(LLVMString::new(err_string.assume_init()));
+ }
+ }
+
+ // Otherwise, it succeeded, so wrap the raw pointer
+ let execution_engine = unsafe { execution_engine.assume_init() };
+ let execution_engine = unsafe { ExecutionEngine::new(Rc::new(execution_engine), true) };
+
+ *self.owned_by_ee.borrow_mut() = Some(execution_engine.clone());
+
+ Ok(execution_engine)
+ }
+
/// Creates a `GlobalValue` based on a type in an address space.
///
/// # Example
@@ -726,11 +858,12 @@ impl<'ctx> Module<'ctx> {
unsafe { MemoryBuffer::new(memory_buffer) }
}
- /// Ensures that the current `Module` is valid, and returns a `Result`
- /// that describes whether or not it is, returning a LLVM allocated string on error.
+ /// Check whether the current [`Module`] is valid.
+ ///
+ /// The error variant is an LLVM-allocated string.
///
/// # Remarks
- /// See also: http://llvm.org/doxygen/Analysis_2Analysis_8cpp_source.html
+ /// See also: [`LLVMVerifyModule`](https://llvm.org/doxygen/group__LLVMCAnalysis.html#ga5645aec2d95116c0432a676db77b2cb0).
pub fn verify(&self) -> Result<(), LLVMString> {
let mut err_str = MaybeUninit::uninit();
@@ -779,7 +912,7 @@ impl<'ctx> Module<'ctx> {
///
/// assert_eq!(*module.get_data_layout(), data_layout);
/// ```
- pub fn get_data_layout(&self) -> Ref {
+ pub fn get_data_layout(&self) -> Ref<'_, DataLayout> {
Ref::map(self.data_layout.borrow(), |l| {
l.as_ref().expect("DataLayout should always exist until Drop")
})
@@ -861,20 +994,7 @@ impl<'ctx> Module<'ctx> {
/// Sets the inline assembly for the `Module`.
pub fn set_inline_assembly(&self, asm: &str) {
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
- {
- use llvm_sys::core::LLVMSetModuleInlineAsm;
-
- let c_string = to_c_str(asm);
-
- unsafe { LLVMSetModuleInlineAsm(self.module.get(), c_string.as_ptr()) }
- }
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- use llvm_sys::core::LLVMSetModuleInlineAsm2;
-
- unsafe { LLVMSetModuleInlineAsm2(self.module.get(), asm.as_ptr() as *const ::libc::c_char, asm.len()) }
- }
+ unsafe { LLVMSetModuleInlineAsm2(self.module.get(), asm.as_ptr() as *const ::libc::c_char, asm.len()) }
}
// REVIEW: Should module take ownership of metadata?
@@ -917,9 +1037,9 @@ impl<'ctx> Module<'ctx> {
/// assert_eq!(md_1[0].into_int_value(), bool_val);
/// assert_eq!(md_1[1].into_float_value(), f32_val);
/// ```
- pub fn add_global_metadata(&self, key: &str, metadata: &MetadataValue<'ctx>) -> Result<(), &'static str> {
+ pub fn add_global_metadata(&self, key: &str, metadata: &MetadataValue<'ctx>) -> Result<(), crate::Error> {
if !metadata.is_node() {
- return Err("metadata is expected to be a node.");
+ return Err(crate::Error::GlobalMetadataError);
}
let c_string = to_c_str(key);
@@ -1244,7 +1364,6 @@ impl<'ctx> Module<'ctx> {
/// assert_eq!(module.get_name().to_str(), Ok("my_mod"));
/// assert_eq!(module.get_source_file_name().to_str(), Ok("my_mod.rs"));
/// ```
- #[llvm_versions(7..)]
pub fn get_source_file_name(&self) -> &CStr {
use llvm_sys::core::LLVMGetSourceFileName;
@@ -1271,7 +1390,6 @@ impl<'ctx> Module<'ctx> {
/// assert_eq!(module.get_name().to_str(), Ok("my_mod"));
/// assert_eq!(module.get_source_file_name().to_str(), Ok("my_mod.rs"));
/// ```
- #[llvm_versions(7..)]
pub fn set_source_file_name(&self, file_name: &str) {
use llvm_sys::core::LLVMSetSourceFileName;
@@ -1331,7 +1449,6 @@ impl<'ctx> Module<'ctx> {
/// Gets the `Comdat` associated with a particular name. If it does not exist, it will be created.
/// A new `Comdat` defaults to a kind of `ComdatSelectionKind::Any`.
- #[llvm_versions(7..)]
pub fn get_or_insert_comdat(&self, name: &str) -> Comdat {
use llvm_sys::comdat::LLVMGetOrInsertComdat;
@@ -1345,7 +1462,6 @@ impl<'ctx> Module<'ctx> {
/// If a `BasicValue` was used to create this flag, it will be wrapped in a `MetadataValue`
/// when returned from this function.
// SubTypes: Might need to return Option, or MV>
- #[llvm_versions(7..)]
pub fn get_flag(&self, key: &str) -> Option> {
use llvm_sys::core::LLVMMetadataAsValue;
@@ -1362,7 +1478,6 @@ impl<'ctx> Module<'ctx> {
/// Append a `MetadataValue` as a module wide flag. Note that using the same key twice
/// will likely invalidate the module.
- #[llvm_versions(7..)]
pub fn add_metadata_flag(&self, key: &str, behavior: FlagBehavior, flag: MetadataValue<'ctx>) {
let md = flag.as_metadata_ref();
@@ -1380,7 +1495,6 @@ impl<'ctx> Module<'ctx> {
/// Append a `BasicValue` as a module wide flag. Note that using the same key twice
/// will likely invalidate the module.
// REVIEW: What happens if value is not const?
- #[llvm_versions(7..)]
pub fn add_basic_value_flag>(&self, key: &str, behavior: FlagBehavior, flag: BV) {
use llvm_sys::core::LLVMValueAsMetadata;
@@ -1398,23 +1512,16 @@ impl<'ctx> Module<'ctx> {
}
/// Strips and debug info from the module, if it exists.
- #[llvm_versions(6..)]
pub fn strip_debug_info(&self) -> bool {
- use llvm_sys::debuginfo::LLVMStripModuleDebugInfo;
-
unsafe { LLVMStripModuleDebugInfo(self.module.get()) == 1 }
}
/// Gets the version of debug metadata contained in this `Module`.
- #[llvm_versions(6..)]
pub fn get_debug_metadata_version(&self) -> libc::c_uint {
- use llvm_sys::debuginfo::LLVMGetModuleDebugMetadataVersion;
-
unsafe { LLVMGetModuleDebugMetadataVersion(self.module.get()) }
}
/// Creates a `DebugInfoBuilder` for this `Module`.
- #[llvm_versions(7..)]
pub fn create_debug_info_builder(
&self,
allow_unresolved: bool,
@@ -1438,7 +1545,9 @@ impl<'ctx> Module<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sysroot: &str,
#[cfg(any(
@@ -1449,7 +1558,9 @@ impl<'ctx> Module<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sdk: &str,
) -> (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>) {
@@ -1476,7 +1587,9 @@ impl<'ctx> Module<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sysroot,
#[cfg(any(
@@ -1487,18 +1600,24 @@ impl<'ctx> Module<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
sdk,
)
}
/// Construct and run a set of passes over a module.
+ ///
/// This function takes a string with the passes that should be used.
- /// The format of this string is the same as opt's -passes argument for the new pass manager.
+ /// The format of this string is the same as
+ /// [`opt`](https://llvm.org/docs/CommandGuide/opt.html)'s
+ /// `-{passes}` argument for the new pass manager.
/// Individual passes may be specified, separated by commas.
- /// Full pipelines may also be invoked using default and friends.
- /// See opt for full reference of the Passes format.
+ /// Full pipelines may also be invoked using `"default"` and friends.
+ /// See [`opt`](https://llvm.org/docs/CommandGuide/opt.html)
+ /// for full reference of the `passes` format.
#[llvm_versions(13..)]
pub fn run_passes(
&self,
@@ -1552,7 +1671,6 @@ impl Drop for Module<'_> {
}
}
-#[llvm_versions(7..)]
#[llvm_enum(LLVMModuleFlagBehavior)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// Defines the operational behavior for a module wide flag. This documentation comes directly
diff --git a/src/passes.rs b/src/passes.rs
index d0fd073dc7f..313624b57ba 100644
--- a/src/passes.rs
+++ b/src/passes.rs
@@ -15,6 +15,8 @@ use llvm_sys::initialization::{LLVMInitializeInstrumentation, LLVMInitializeObjC
use llvm_sys::prelude::LLVMPassManagerRef;
#[llvm_versions(..=16)]
use llvm_sys::prelude::LLVMPassRegistryRef;
+#[llvm_versions(..=15)]
+use llvm_sys::transforms::aggressive_instcombine::LLVMAddAggressiveInstCombinerPass;
#[llvm_versions(10..=16)]
use llvm_sys::transforms::ipo::LLVMAddMergeFunctionsPass;
#[llvm_versions(..=15)]
@@ -466,26 +468,6 @@ impl PassManager {
unsafe { LLVMAddStripSymbolsPass(self.pass_manager) }
}
- /// This pass combines instructions inside basic blocks to form
- /// vector instructions. It iterates over each basic block,
- /// attempting to pair compatible instructions, repeating this
- /// process until no additional pairs are selected for vectorization.
- /// When the outputs of some pair of compatible instructions are
- /// used as inputs by some other pair of compatible instructions,
- /// those pairs are part of a potential vectorization chain.
- /// Instruction pairs are only fused into vector instructions when
- /// they are part of a chain longer than some threshold length.
- /// Moreover, the pass attempts to find the best possible chain
- /// for each pair of compatible instructions. These heuristics
- /// are intended to prevent vectorization in cases where it would
- /// not yield a performance increase of the resulting code.
- #[cfg(feature = "llvm4-0")]
- pub fn add_bb_vectorize_pass(&self) {
- use llvm_sys::transforms::vectorize::LLVMAddBBVectorizePass;
-
- unsafe { LLVMAddBBVectorizePass(self.pass_manager) }
- }
-
/// No LLVM documentation is available at this time.
#[llvm_versions(..=16)]
pub fn add_loop_vectorize_pass(&self) {
@@ -636,7 +618,7 @@ impl PassManager {
/// right-hand side.
///
/// 2. Bitwise operators with constant operands are always grouped so that
- /// shifts are performed first, then ors, then ands, then xors.
+ /// shifts are performed first, then ORs, then ANDs, then XORs.
///
/// 3. Compare instructions are converted from <, >, ≤, or ≥ to = or ≠if possible.
///
@@ -806,9 +788,6 @@ impl PassManager {
/// switch instruction until it is convenient.
#[llvm_versions(..=16)]
pub fn add_lower_switch_pass(&self) {
- #[llvm_versions(..=6)]
- use llvm_sys::transforms::scalar::LLVMAddLowerSwitchPass;
- #[llvm_versions(7..=16)]
use llvm_sys::transforms::util::LLVMAddLowerSwitchPass;
unsafe { LLVMAddLowerSwitchPass(self.pass_manager) }
@@ -822,9 +801,6 @@ impl PassManager {
/// the standard SSA construction algorithm to construct "pruned" SSA form.
#[llvm_versions(..=16)]
pub fn add_promote_memory_to_register_pass(&self) {
- #[llvm_versions(..=6)]
- use llvm_sys::transforms::scalar::LLVMAddPromoteMemoryToRegisterPass;
- #[llvm_versions(7..=16)]
use llvm_sys::transforms::util::LLVMAddPromoteMemoryToRegisterPass;
unsafe { LLVMAddPromoteMemoryToRegisterPass(self.pass_manager) }
@@ -906,7 +882,7 @@ impl PassManager {
/// returns something else (like constant 0), and can still be TRE’d. It can be
/// TRE'd if all other return instructions in the function return the exact same value.
///
- /// 4. If it can prove that callees do not access theier caller stack frame,
+ /// 4. If it can prove that callees do not access their caller stack frame,
/// they are marked as eligible for tail call elimination (by the code generator).
#[llvm_versions(..=16)]
pub fn add_tail_call_elimination_pass(&self) {
@@ -1071,45 +1047,40 @@ impl PassManager {
unsafe { LLVMAddBasicAliasAnalysisPass(self.pass_manager) }
}
- #[llvm_versions(7..=15)]
+ #[llvm_versions(..=15)]
pub fn add_aggressive_inst_combiner_pass(&self) {
- #[cfg(not(feature = "llvm7-0"))]
- use llvm_sys::transforms::aggressive_instcombine::LLVMAddAggressiveInstCombinerPass;
- #[cfg(feature = "llvm7-0")]
- use llvm_sys::transforms::scalar::LLVMAddAggressiveInstCombinerPass;
-
unsafe { LLVMAddAggressiveInstCombinerPass(self.pass_manager) }
}
- #[llvm_versions(7..=16)]
+ #[llvm_versions(..=16)]
pub fn add_loop_unroll_and_jam_pass(&self) {
use llvm_sys::transforms::scalar::LLVMAddLoopUnrollAndJamPass;
unsafe { LLVMAddLoopUnrollAndJamPass(self.pass_manager) }
}
- #[llvm_versions(8..15)]
+ #[llvm_versions(..15)]
pub fn add_coroutine_early_pass(&self) {
use llvm_sys::transforms::coroutines::LLVMAddCoroEarlyPass;
unsafe { LLVMAddCoroEarlyPass(self.pass_manager) }
}
- #[llvm_versions(8..15)]
+ #[llvm_versions(..15)]
pub fn add_coroutine_split_pass(&self) {
use llvm_sys::transforms::coroutines::LLVMAddCoroSplitPass;
unsafe { LLVMAddCoroSplitPass(self.pass_manager) }
}
- #[llvm_versions(8..15)]
+ #[llvm_versions(..15)]
pub fn add_coroutine_elide_pass(&self) {
use llvm_sys::transforms::coroutines::LLVMAddCoroElidePass;
unsafe { LLVMAddCoroElidePass(self.pass_manager) }
}
- #[llvm_versions(8..15)]
+ #[llvm_versions(..15)]
pub fn add_coroutine_cleanup_pass(&self) {
use llvm_sys::transforms::coroutines::LLVMAddCoroCleanupPass;
@@ -1199,7 +1170,7 @@ impl PassRegistry {
unsafe { LLVMInitializeTarget(self.pass_registry) }
}
- #[llvm_versions(7..=15)]
+ #[llvm_versions(..=15)]
pub fn initialize_aggressive_inst_combiner(&self) {
use llvm_sys::initialization::LLVMInitializeAggressiveInstCombiner;
diff --git a/src/support/mod.rs b/src/support/mod.rs
index 0c3941e6a9c..d6ea212f781 100644
--- a/src/support/mod.rs
+++ b/src/support/mod.rs
@@ -43,7 +43,7 @@ impl LLVMString {
/// This method will allocate a c string through LLVM
pub(crate) fn create_from_str(string: &str) -> LLVMString {
- debug_assert_eq!(string.as_bytes()[string.as_bytes().len() - 1], 0);
+ debug_assert_eq!(string.as_bytes()[string.len() - 1], 0);
unsafe { LLVMString::new(LLVMCreateMessage(string.as_ptr() as *const _)) }
}
diff --git a/src/targets.rs b/src/targets.rs
index 5edc005632a..6b8932456ca 100644
--- a/src/targets.rs
+++ b/src/targets.rs
@@ -784,7 +784,6 @@ impl Target {
}
#[cfg(feature = "target-webassembly")]
- #[llvm_versions(8..)]
pub fn initialize_webassembly(config: &InitializationConfig) {
use llvm_sys::target::{
LLVMInitializeWebAssemblyAsmParser, LLVMInitializeWebAssemblyAsmPrinter,
@@ -1094,7 +1093,6 @@ impl TargetMachine {
unsafe { TargetTriple::new(llvm_string) }
}
- #[llvm_versions(7..)]
pub fn normalize_triple(triple: &TargetTriple) -> TargetTriple {
use llvm_sys::target_machine::LLVMNormalizeTargetTriple;
@@ -1108,7 +1106,6 @@ impl TargetMachine {
/// # Example Output
///
/// `x86_64-pc-linux-gnu`
- #[llvm_versions(7..)]
pub fn get_host_cpu_name() -> LLVMString {
use llvm_sys::target_machine::LLVMGetHostCPUName;
@@ -1120,7 +1117,6 @@ impl TargetMachine {
/// # Example Output
///
/// `+sse2,+cx16,+sahf,-tbm`
- #[llvm_versions(7..)]
pub fn get_host_cpu_features() -> LLVMString {
use llvm_sys::target_machine::LLVMGetHostCPUFeatures;
diff --git a/src/types/array_type.rs b/src/types/array_type.rs
index 85568f3009c..c849536ac3b 100644
--- a/src/types/array_type.rs
+++ b/src/types/array_type.rs
@@ -77,27 +77,17 @@ impl<'ctx> ArrayType<'ctx> {
/// let i8_array_type = i8_type.array_type(3);
/// let i8_array_ptr_type = i8_array_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(i8_array_ptr_type.get_element_type().into_array_type(), i8_array_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
diff --git a/src/types/enums.rs b/src/types/enums.rs
index d17394698d4..cf116754b9e 100644
--- a/src/types/enums.rs
+++ b/src/types/enums.rs
@@ -72,7 +72,7 @@ enum_type_set! {
StructType,
/// A contiguous homogeneous "SIMD" container type.
VectorType,
- /// A contiguous homogenous scalable "SIMD" container type.
+ /// A contiguous homogeneous scalable "SIMD" container type.
ScalableVectorType,
/// A valueless type.
VoidType,
@@ -93,7 +93,7 @@ enum_type_set! {
StructType,
/// A contiguous homogeneous "SIMD" container type.
VectorType,
- /// A contiguous homogenous scalable "SIMD" container type.
+ /// A contiguous homogeneous scalable "SIMD" container type.
ScalableVectorType,
}
}
@@ -111,11 +111,27 @@ enum_type_set! {
}
impl<'ctx> BasicMetadataTypeEnum<'ctx> {
+ /// Create [`BasicMetadataTypeEnum`] from [`LLVMTypeRef`].
+ ///
+ /// # Safety
+ ///
+ /// Undefined behavior if the referenced type cannot be represented as [`BasicMetadataTypeEnum`],
+ /// or the underlying pointer is null.
+ ///
+ /// Before LLVM 6, [`BasicMetadataTypeEnum::MetadataType`] variants cannot be created
+ /// with this function. Attempting to do results in undefined behavior.
+ pub unsafe fn new(type_: LLVMTypeRef) -> Self {
+ match LLVMGetTypeKind(type_) {
+ LLVMTypeKind::LLVMMetadataTypeKind => Self::MetadataType(MetadataType::new(type_)),
+ _ => BasicTypeEnum::new(type_).into(),
+ }
+ }
+
pub fn into_array_type(self) -> ArrayType<'ctx> {
if let BasicMetadataTypeEnum::ArrayType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -123,7 +139,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::FloatType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -131,7 +147,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::IntType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -139,7 +155,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::PointerType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -147,7 +163,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::StructType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -155,7 +171,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::VectorType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -163,7 +179,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::ScalableVectorType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -171,7 +187,7 @@ impl<'ctx> BasicMetadataTypeEnum<'ctx> {
if let BasicMetadataTypeEnum::MetadataType(t) = self {
t
} else {
- panic!("Found {:?} but expected another variant", self);
+ panic!("Found {self:?} but expected another variant");
}
}
@@ -244,7 +260,9 @@ impl<'ctx> AnyTypeEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
@@ -262,11 +280,15 @@ impl<'ctx> AnyTypeEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::ScalableVectorType(ScalableVectorType::new(type_)),
// FIXME: should inkwell support metadata as AnyType?
LLVMTypeKind::LLVMMetadataTypeKind => panic!("Metadata type is not supported as AnyType."),
+
+ #[cfg(not(feature = "llvm20-1"))]
LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
#[cfg(any(
feature = "llvm12-0",
@@ -275,11 +297,19 @@ impl<'ctx> AnyTypeEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMX86_AMXTypeKind => panic!("FIXME: Unsupported type: AMX"),
LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
- #[cfg(any(feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ #[cfg(any(
+ feature = "llvm16-0",
+ feature = "llvm17-0",
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
+ ))]
LLVMTypeKind::LLVMTargetExtTypeKind => panic!("FIXME: Unsupported type: TargetExt"),
}
}
@@ -293,7 +323,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::ArrayType(t) = self {
t
} else {
- panic!("Found {:?} but expected the ArrayType variant", self);
+ panic!("Found {self:?} but expected the ArrayType variant");
}
}
@@ -301,7 +331,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::FloatType(t) = self {
t
} else {
- panic!("Found {:?} but expected the FloatType variant", self);
+ panic!("Found {self:?} but expected the FloatType variant");
}
}
@@ -309,7 +339,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::FunctionType(t) = self {
t
} else {
- panic!("Found {:?} but expected the FunctionType variant", self);
+ panic!("Found {self:?} but expected the FunctionType variant");
}
}
@@ -317,7 +347,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::IntType(t) = self {
t
} else {
- panic!("Found {:?} but expected the IntType variant", self);
+ panic!("Found {self:?} but expected the IntType variant");
}
}
@@ -325,7 +355,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::PointerType(t) = self {
t
} else {
- panic!("Found {:?} but expected the PointerType variant", self);
+ panic!("Found {self:?} but expected the PointerType variant");
}
}
@@ -333,7 +363,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::StructType(t) = self {
t
} else {
- panic!("Found {:?} but expected the StructType variant", self);
+ panic!("Found {self:?} but expected the StructType variant");
}
}
@@ -341,7 +371,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::VectorType(t) = self {
t
} else {
- panic!("Found {:?} but expected the VectorType variant", self);
+ panic!("Found {self:?} but expected the VectorType variant");
}
}
@@ -349,7 +379,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::ScalableVectorType(t) = self {
t
} else {
- panic!("Found {:?} but expected the ScalableVectorType variant", self);
+ panic!("Found {self:?} but expected the ScalableVectorType variant");
}
}
@@ -357,7 +387,7 @@ impl<'ctx> AnyTypeEnum<'ctx> {
if let AnyTypeEnum::VoidType(t) = self {
t
} else {
- panic!("Found {:?} but expected the VoidType variant", self);
+ panic!("Found {self:?} but expected the VoidType variant");
}
}
@@ -444,7 +474,9 @@ impl<'ctx> BasicTypeEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
@@ -460,13 +492,16 @@ impl<'ctx> BasicTypeEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMScalableVectorTypeKind => {
BasicTypeEnum::ScalableVectorType(ScalableVectorType::new(type_))
},
LLVMTypeKind::LLVMMetadataTypeKind => panic!("Unsupported basic type: Metadata"),
// see https://llvm.org/docs/LangRef.html#x86-mmx-type
+ #[cfg(not(feature = "llvm20-1"))]
LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("Unsupported basic type: MMX"),
// see https://llvm.org/docs/LangRef.html#x86-amx-type
#[cfg(any(
@@ -476,14 +511,22 @@ impl<'ctx> BasicTypeEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMX86_AMXTypeKind => unreachable!("Unsupported basic type: AMX"),
LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
- #[cfg(any(feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ #[cfg(any(
+ feature = "llvm16-0",
+ feature = "llvm17-0",
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
+ ))]
LLVMTypeKind::LLVMTargetExtTypeKind => unreachable!("Unsupported basic type: TargetExt"),
}
}
@@ -492,7 +535,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::ArrayType(t) = self {
t
} else {
- panic!("Found {:?} but expected the ArrayType variant", self);
+ panic!("Found {self:?} but expected the ArrayType variant");
}
}
@@ -500,7 +543,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::FloatType(t) = self {
t
} else {
- panic!("Found {:?} but expected the FloatType variant", self);
+ panic!("Found {self:?} but expected the FloatType variant");
}
}
@@ -508,7 +551,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::IntType(t) = self {
t
} else {
- panic!("Found {:?} but expected the IntType variant", self);
+ panic!("Found {self:?} but expected the IntType variant");
}
}
@@ -516,7 +559,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::PointerType(t) = self {
t
} else {
- panic!("Found {:?} but expected the PointerType variant", self);
+ panic!("Found {self:?} but expected the PointerType variant");
}
}
@@ -524,7 +567,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::StructType(t) = self {
t
} else {
- panic!("Found {:?} but expected the StructType variant", self);
+ panic!("Found {self:?} but expected the StructType variant");
}
}
@@ -532,7 +575,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::VectorType(t) = self {
t
} else {
- panic!("Found {:?} but expected the VectorType variant", self);
+ panic!("Found {self:?} but expected the VectorType variant");
}
}
@@ -540,7 +583,7 @@ impl<'ctx> BasicTypeEnum<'ctx> {
if let BasicTypeEnum::ScalableVectorType(t) = self {
t
} else {
- panic!("Found {:?} but expected the ScalableVectorType variant", self);
+ panic!("Found {self:?} but expected the ScalableVectorType variant");
}
}
diff --git a/src/types/float_type.rs b/src/types/float_type.rs
index 3de4f2d11ce..73c93cadffe 100644
--- a/src/types/float_type.rs
+++ b/src/types/float_type.rs
@@ -1,4 +1,4 @@
-use llvm_sys::core::{LLVMConstReal, LLVMConstRealOfStringAndSize};
+use llvm_sys::core::{LLVMConstReal, LLVMConstRealOfStringAndSize, LLVMGetTypeKind};
use llvm_sys::execution_engine::LLVMCreateGenericValueOfFloat;
use llvm_sys::prelude::LLVMTypeRef;
@@ -6,7 +6,9 @@ use crate::context::ContextRef;
use crate::support::LLVMString;
use crate::types::enums::BasicMetadataTypeEnum;
use crate::types::traits::AsTypeRef;
-use crate::types::{ArrayType, FunctionType, PointerType, ScalableVectorType, Type, VectorType};
+#[llvm_versions(12..)]
+use crate::types::ScalableVectorType;
+use crate::types::{ArrayType, FunctionType, PointerType, Type, VectorType};
use crate::values::{ArrayValue, FloatValue, GenericValue, IntValue};
use crate::AddressSpace;
@@ -64,7 +66,7 @@ impl<'ctx> FloatType<'ctx> {
self.float_type.array_type(size)
}
- /// Creates a `ScalableVectorType` with this `FloatType` for its element type.
+ /// Creates a `VectorType` with this `FloatType` for its element type.
///
/// # Example
///
@@ -234,27 +236,17 @@ impl<'ctx> FloatType<'ctx> {
/// let f32_type = context.f32_type();
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
@@ -264,6 +256,41 @@ impl<'ctx> FloatType<'ctx> {
self.float_type.ptr_type(address_space)
}
+ /// Gets the bit width of a `FloatType`.
+ ///
+ /// # Example
+ /// ```no_run
+ /// use inkwell::context::Context;
+ ///
+ /// let context = Context::create();
+ /// let f128_type = context.f128_type();
+ ///
+ /// assert_eq!(f128_type.get_bit_width(), 128);
+ /// ```
+ pub fn get_bit_width(self) -> u32 {
+ let type_kind = unsafe { LLVMGetTypeKind(self.as_type_ref()) };
+
+ match type_kind {
+ llvm_sys::LLVMTypeKind::LLVMHalfTypeKind => 16,
+ #[cfg(any(
+ feature = "llvm11-0",
+ feature = "llvm12-0",
+ feature = "llvm13-0",
+ feature = "llvm14-0",
+ feature = "llvm15-0",
+ feature = "llvm16-0",
+ feature = "llvm17-0",
+ feature = "llvm18-1"
+ ))]
+ llvm_sys::LLVMTypeKind::LLVMBFloatTypeKind => 16,
+ llvm_sys::LLVMTypeKind::LLVMFloatTypeKind => 32,
+ llvm_sys::LLVMTypeKind::LLVMDoubleTypeKind => 64,
+ llvm_sys::LLVMTypeKind::LLVMX86_FP80TypeKind => 80,
+ llvm_sys::LLVMTypeKind::LLVMFP128TypeKind | llvm_sys::LLVMTypeKind::LLVMPPC_FP128TypeKind => 128,
+ _ => unreachable!(),
+ }
+ }
+
/// Print the definition of a `FloatType` to `LLVMString`.
pub fn print_to_string(self) -> LLVMString {
self.float_type.print_to_string()
diff --git a/src/types/fn_type.rs b/src/types/fn_type.rs
index 25f3e8c92f3..78c5245d97e 100644
--- a/src/types/fn_type.rs
+++ b/src/types/fn_type.rs
@@ -10,7 +10,7 @@ use std::mem::forget;
use crate::context::ContextRef;
use crate::support::LLVMString;
use crate::types::traits::AsTypeRef;
-use crate::types::{AnyType, BasicTypeEnum, PointerType, Type};
+use crate::types::{AnyType, BasicMetadataTypeEnum, BasicTypeEnum, PointerType, Type};
use crate::AddressSpace;
/// A `FunctionType` is the type of a function variable.
@@ -45,27 +45,17 @@ impl<'ctx> FunctionType<'ctx> {
/// let fn_type = f32_type.fn_type(&[], false);
/// let fn_ptr_type = fn_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
@@ -96,7 +86,7 @@ impl<'ctx> FunctionType<'ctx> {
///
/// # Example
///
- /// ```no_run
+ /// ```
/// use inkwell::context::Context;
///
/// let context = Context::create();
@@ -107,7 +97,7 @@ impl<'ctx> FunctionType<'ctx> {
/// assert_eq!(param_types.len(), 1);
/// assert_eq!(param_types[0].into_float_type(), f32_type);
/// ```
- pub fn get_param_types(self) -> Vec> {
+ pub fn get_param_types(self) -> Vec> {
let count = self.count_param_types();
let mut raw_vec: Vec = Vec::with_capacity(count as usize);
let ptr = raw_vec.as_mut_ptr();
@@ -120,7 +110,10 @@ impl<'ctx> FunctionType<'ctx> {
Vec::from_raw_parts(ptr, count as usize, count as usize)
};
- raw_vec.iter().map(|val| unsafe { BasicTypeEnum::new(*val) }).collect()
+ raw_vec
+ .iter()
+ .map(|val| unsafe { BasicMetadataTypeEnum::new(*val) })
+ .collect()
}
/// Counts the number of param types this `FunctionType` has.
diff --git a/src/types/int_type.rs b/src/types/int_type.rs
index 95f43a670b2..fe513635fdf 100644
--- a/src/types/int_type.rs
+++ b/src/types/int_type.rs
@@ -7,7 +7,9 @@ use llvm_sys::prelude::LLVMTypeRef;
use crate::context::ContextRef;
use crate::support::LLVMString;
use crate::types::traits::AsTypeRef;
-use crate::types::{ArrayType, FunctionType, PointerType, ScalableVectorType, Type, VectorType};
+#[llvm_versions(12..)]
+use crate::types::ScalableVectorType;
+use crate::types::{ArrayType, FunctionType, PointerType, Type, VectorType};
use crate::values::{ArrayValue, GenericValue, IntValue};
use crate::AddressSpace;
@@ -321,27 +323,17 @@ impl<'ctx> IntType<'ctx> {
/// let i8_type = context.i8_type();
/// let i8_ptr_type = i8_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(i8_ptr_type.get_element_type().into_int_type(), i8_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
diff --git a/src/types/metadata_type.rs b/src/types/metadata_type.rs
index db53342187c..c679541dc7a 100644
--- a/src/types/metadata_type.rs
+++ b/src/types/metadata_type.rs
@@ -19,7 +19,6 @@ impl<'ctx> MetadataType<'ctx> {
///
/// # Safety
/// Undefined behavior, if referenced type isn't metadata type
- #[llvm_versions(6..)]
pub unsafe fn new(metadata_type: LLVMTypeRef) -> Self {
assert!(!metadata_type.is_null());
@@ -39,7 +38,6 @@ impl<'ctx> MetadataType<'ctx> {
/// let md_type = context.metadata_type();
/// let fn_type = md_type.fn_type(&[], false);
/// ```
- #[llvm_versions(6..)]
pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
self.metadata_type.fn_type(param_types, is_var_args)
}
@@ -56,7 +54,6 @@ impl<'ctx> MetadataType<'ctx> {
///
/// assert_eq!(md_type.get_context(), context);
/// ```
- #[llvm_versions(6..)]
pub fn get_context(self) -> ContextRef<'ctx> {
self.metadata_type.get_context()
}
@@ -68,15 +65,9 @@ impl<'ctx> MetadataType<'ctx> {
}
unsafe impl AsTypeRef for MetadataType<'_> {
- #[llvm_versions(6..)]
fn as_type_ref(&self) -> LLVMTypeRef {
self.metadata_type.ty
}
-
- #[llvm_versions(..=5)]
- fn as_type_ref(&self) -> LLVMTypeRef {
- unimplemented!("MetadataType is only available in LLVM > 6.0")
- }
}
impl Display for MetadataType<'_> {
diff --git a/src/types/ptr_type.rs b/src/types/ptr_type.rs
index 575aeae5bd0..69826df2aa9 100644
--- a/src/types/ptr_type.rs
+++ b/src/types/ptr_type.rs
@@ -6,9 +6,11 @@ use llvm_sys::prelude::LLVMTypeRef;
use crate::context::ContextRef;
use crate::support::LLVMString;
use crate::types::traits::AsTypeRef;
-#[llvm_versions(..=14)]
+#[cfg(feature = "typed-pointers")]
use crate::types::AnyTypeEnum;
-use crate::types::{ArrayType, FunctionType, ScalableVectorType, Type, VectorType};
+#[llvm_versions(12..)]
+use crate::types::ScalableVectorType;
+use crate::types::{ArrayType, FunctionType, Type, VectorType};
use crate::values::{ArrayValue, IntValue, PointerValue};
use crate::AddressSpace;
@@ -44,9 +46,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_type_size = f32_ptr_type.size_of();
/// ```
@@ -64,9 +66,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_type_alignment = f32_ptr_type.get_alignment();
/// ```
@@ -84,33 +86,23 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_ptr_type = f32_ptr_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(f32_ptr_ptr_type.get_element_type().into_pointer_type(), f32_ptr_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
@@ -130,9 +122,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
///
/// assert_eq!(f32_ptr_type.get_context(), context);
@@ -152,9 +144,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = f32_ptr_type.fn_type(&[], false);
/// ```
@@ -172,9 +164,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_array_type = f32_ptr_type.array_type(3);
///
@@ -195,9 +187,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
///
/// assert_eq!(f32_ptr_type.get_address_space(), AddressSpace::default());
@@ -224,9 +216,9 @@ impl<'ctx> PointerType<'ctx> {
/// // Local Context
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_null = f32_ptr_type.const_null();
///
@@ -249,9 +241,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_zero = f32_ptr_type.const_zero();
/// ```
@@ -268,9 +260,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_undef = f32_ptr_type.get_undef();
///
@@ -290,9 +282,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_undef = f32_ptr_type.get_poison();
///
@@ -313,9 +305,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_vec_type = f32_ptr_type.vec_type(3);
///
@@ -336,9 +328,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_scalable_vec_type = f32_ptr_type.scalable_vec_type(3);
///
@@ -361,14 +353,15 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
///
/// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type);
/// ```
- #[llvm_versions(..=14)]
+ #[llvm_versions(..=16)]
+ #[cfg(feature = "typed-pointers")]
pub fn get_element_type(self) -> AnyTypeEnum<'ctx> {
self.ptr_type.get_element_type()
}
@@ -382,9 +375,9 @@ impl<'ctx> PointerType<'ctx> {
///
/// let context = Context::create();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let f32_ptr_val = f32_ptr_type.const_null();
/// let f32_ptr_array = f32_ptr_type.const_array(&[f32_ptr_val, f32_ptr_val]);
diff --git a/src/types/scalable_vec_type.rs b/src/types/scalable_vec_type.rs
index b4890768158..344068ba887 100644
--- a/src/types/scalable_vec_type.rs
+++ b/src/types/scalable_vec_type.rs
@@ -172,27 +172,17 @@ impl<'ctx> ScalableVectorType<'ctx> {
/// let f32_scalable_vec_type = f32_type.scalable_vec_type(3);
/// let f32_scalable_vec_ptr_type = f32_scalable_vec_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(f32_scalable_vec_ptr_type.get_element_type().into_scalable_vector_type(), f32_scalable_vec_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
diff --git a/src/types/struct_type.rs b/src/types/struct_type.rs
index 56e24251569..99d54f651c1 100644
--- a/src/types/struct_type.rs
+++ b/src/types/struct_type.rs
@@ -201,27 +201,17 @@ impl<'ctx> StructType<'ctx> {
/// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
/// let struct_ptr_type = struct_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(struct_ptr_type.get_element_type().into_struct_type(), struct_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
diff --git a/src/types/traits.rs b/src/types/traits.rs
index 368b4d68e0d..1fd694c8383 100644
--- a/src/types/traits.rs
+++ b/src/types/traits.rs
@@ -134,10 +134,12 @@ pub unsafe trait BasicType<'ctx>: AnyType<'ctx> {
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
diff --git a/src/types/vec_type.rs b/src/types/vec_type.rs
index 28ccd1f4b70..c32180c60b7 100644
--- a/src/types/vec_type.rs
+++ b/src/types/vec_type.rs
@@ -200,27 +200,17 @@ impl<'ctx> VectorType<'ctx> {
/// let f32_vec_type = f32_type.vec_type(3);
/// let f32_vec_ptr_type = f32_vec_type.ptr_type(AddressSpace::default());
///
- /// #[cfg(any(
- /// feature = "llvm4-0",
- /// feature = "llvm5-0",
- /// feature = "llvm6-0",
- /// feature = "llvm7-0",
- /// feature = "llvm8-0",
- /// feature = "llvm9-0",
- /// feature = "llvm10-0",
- /// feature = "llvm11-0",
- /// feature = "llvm12-0",
- /// feature = "llvm13-0",
- /// feature = "llvm14-0"
- /// ))]
+ /// #[cfg(feature = "typed-pointers")]
/// assert_eq!(f32_vec_ptr_type.get_element_type().into_vector_type(), f32_vec_type);
/// ```
#[cfg_attr(
any(
- feature = "llvm15-0",
- feature = "llvm16-0",
+ all(feature = "llvm15-0", not(feature = "typed-pointers")),
+ all(feature = "llvm16-0", not(feature = "typed-pointers")),
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
),
deprecated(
note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
diff --git a/src/values/array_value.rs b/src/values/array_value.rs
index c6d7c44d6d4..47836f6221c 100644
--- a/src/values/array_value.rs
+++ b/src/values/array_value.rs
@@ -129,6 +129,33 @@ impl<'ctx> ArrayValue<'ctx> {
unsafe { LLVMIsConstantString(self.as_value_ref()) == 1 }
}
+ /// Obtain the string from the ArrayValue
+ /// if the value points to a constant string.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use inkwell::context::Context;
+ /// use std::ffi::CStr;
+ ///
+ /// let context = Context::create();
+ /// let string = context.const_string(b"hello!", false);
+ ///
+ /// let result = b"hello!".as_slice();
+ /// assert_eq!(string.as_const_string(), Some(result));
+ /// ```
+ // SubTypes: Impl only for ArrayValue>
+ pub fn as_const_string(&self) -> Option<&[u8]> {
+ let mut len = 0;
+ let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) };
+
+ if ptr.is_null() {
+ None
+ } else {
+ unsafe { Some(std::slice::from_raw_parts(ptr.cast(), len)) }
+ }
+ }
+
/// Obtain the string from the ArrayValue
/// if the value points to a constant string.
///
@@ -145,6 +172,7 @@ impl<'ctx> ArrayValue<'ctx> {
/// assert_eq!(string.get_string_constant(), Some(result));
/// ```
// SubTypes: Impl only for ArrayValue>
+ #[deprecated = "llvm strings can contain internal NULs, and this function truncates such values, use as_const_string instead"]
pub fn get_string_constant(&self) -> Option<&CStr> {
let mut len = 0;
let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) };
diff --git a/src/values/basic_value_use.rs b/src/values/basic_value_use.rs
index 32591293770..e847c9f004b 100644
--- a/src/values/basic_value_use.rs
+++ b/src/values/basic_value_use.rs
@@ -40,9 +40,9 @@ impl<'ctx> BasicValueUse<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -104,9 +104,9 @@ impl<'ctx> BasicValueUse<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -143,9 +143,9 @@ impl<'ctx> BasicValueUse<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
diff --git a/src/values/call_site_value.rs b/src/values/call_site_value.rs
index 7d307ef34ed..212e29f2741 100644
--- a/src/values/call_site_value.rs
+++ b/src/values/call_site_value.rs
@@ -1,8 +1,10 @@
use std::fmt::{self, Display};
use either::Either;
+
+use llvm_sys::core::LLVMGetCalledFunctionType;
use llvm_sys::core::{
- LLVMGetInstructionCallConv, LLVMGetTypeKind, LLVMIsTailCall, LLVMSetInstrParamAlignment,
+ LLVMGetCalledValue, LLVMGetInstructionCallConv, LLVMGetTypeKind, LLVMIsTailCall, LLVMSetInstrParamAlignment,
LLVMSetInstructionCallConv, LLVMSetTailCall, LLVMTypeOf,
};
#[llvm_versions(18..)]
@@ -11,6 +13,7 @@ use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::LLVMTypeKind;
use crate::attributes::{Attribute, AttributeLoc};
+use crate::types::FunctionType;
#[llvm_versions(18..)]
use crate::values::operand_bundle::OperandBundleIter;
use crate::values::{AsValueRef, BasicValueEnum, FunctionValue, InstructionValue, Value};
@@ -201,9 +204,12 @@ impl<'ctx> CallSiteValue<'ctx> {
/// Gets the `FunctionValue` this `CallSiteValue` is based on.
///
+ /// Returns [`None`] if the call this value bases on is indirect or the retrieved function
+ /// value doesn't have the same type as the underlying call instruction.
+ ///
/// # Example
///
- /// ```no_run
+ /// ```
/// use inkwell::context::Context;
///
/// let context = Context::create();
@@ -220,12 +226,57 @@ impl<'ctx> CallSiteValue<'ctx> {
///
/// let call_site_value = builder.build_call(fn_value, &[], "my_fn").unwrap();
///
- /// assert_eq!(call_site_value.get_called_fn_value(), fn_value);
+ /// assert_eq!(call_site_value.get_called_fn_value(), Some(fn_value));
+ /// ```
+ pub fn get_called_fn_value(self) -> Option> {
+ // SAFETY: the passed LLVMValueRef is of type CallSite
+ let called_value = unsafe { LLVMGetCalledValue(self.as_value_ref()) };
+
+ let fn_value = unsafe { FunctionValue::new(called_value) };
+
+ // Check that the retrieved function value has the same type as the callee.
+ // This matches the behavior of the C++ API `CallBase::getCalledFunction`.
+ // This is only possible on LLVM >=8, where the `LLVMGetCalledFunctionType` API exists.
+ self.get_called_fn_value_check_type_consistency(fn_value)
+ }
+
+ #[inline]
+ fn get_called_fn_value_check_type_consistency(
+ &self,
+ fn_value: Option>,
+ ) -> Option> {
+ fn_value.filter(|fn_value| fn_value.get_type() == self.get_called_fn_type())
+ }
+
+ /// Gets the type of the function called by the instruction this `CallSiteValue` is based on.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use inkwell::context::Context;
+ ///
+ /// let context = Context::create();
+ /// let builder = context.create_builder();
+ /// let module = context.create_module("my_mod");
+ /// let i32_type = context.i32_type();
+ /// let fn_type = i32_type.fn_type(&[], false);
+ /// let fn_value = module.add_function("my_fn", fn_type, None);
+ ///
+ /// let entry_bb = context.append_basic_block(fn_value, "entry");
+ /// builder.position_at_end(entry_bb);
+ ///
+ /// // Recursive call.
+ /// let call_site_value = builder.build_call(fn_value, &[], "my_fn").unwrap();
+ ///
+ /// assert_eq!(call_site_value.get_called_fn_type(), fn_type);
/// ```
- pub fn get_called_fn_value(self) -> FunctionValue<'ctx> {
- use llvm_sys::core::LLVMGetCalledValue;
+ pub fn get_called_fn_type(self) -> FunctionType<'ctx> {
+ // SAFETY: the passed LLVMValueRef is of type CallSite
+ let fn_type_ref = unsafe { LLVMGetCalledFunctionType(self.as_value_ref()) };
- unsafe { FunctionValue::new(LLVMGetCalledValue(self.as_value_ref())).expect("This should never be null?") }
+ // FIXME?: this assumes that fn_type_ref is not null.
+ // SAFETY: fn_type_ref is a function type reference.
+ unsafe { FunctionType::new(fn_type_ref) }
}
/// Counts the number of `Attribute`s on this `CallSiteValue` at an index.
diff --git a/src/values/callable_value.rs b/src/values/callable_value.rs
index b7ae7c3a0d8..2595b76ba59 100644
--- a/src/values/callable_value.rs
+++ b/src/values/callable_value.rs
@@ -79,7 +79,7 @@ use llvm_sys::LLVMTypeKind;
#[derive(Debug)]
pub struct CallableValue<'ctx>(Either, PointerValue<'ctx>>);
-unsafe impl<'ctx> AsValueRef for CallableValue<'ctx> {
+unsafe impl AsValueRef for CallableValue<'_> {
fn as_value_ref(&self) -> LLVMValueRef {
use either::Either::*;
@@ -92,7 +92,7 @@ unsafe impl<'ctx> AsValueRef for CallableValue<'ctx> {
unsafe impl<'ctx> AnyValue<'ctx> for CallableValue<'ctx> {}
-unsafe impl<'ctx> AsTypeRef for CallableValue<'ctx> {
+unsafe impl AsTypeRef for CallableValue<'_> {
fn as_type_ref(&self) -> LLVMTypeRef {
use either::Either::*;
@@ -103,7 +103,7 @@ unsafe impl<'ctx> AsTypeRef for CallableValue<'ctx> {
}
}
-impl<'ctx> CallableValue<'ctx> {
+impl CallableValue<'_> {
#[llvm_versions(..=14)]
pub(crate) fn returns_void(&self) -> bool {
use llvm_sys::core::LLVMGetReturnType;
diff --git a/src/values/enums.rs b/src/values/enums.rs
index b0a29933c3a..13bc82eb9a1 100644
--- a/src/values/enums.rs
+++ b/src/values/enums.rs
@@ -102,7 +102,9 @@ impl<'ctx> AnyValueEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMScalableVectorTypeKind => {
AnyValueEnum::ScalableVectorValue(ScalableVectorValue::new(value))
@@ -163,83 +165,93 @@ impl<'ctx> AnyValueEnum<'ctx> {
matches!(self, AnyValueEnum::InstructionValue(_))
}
+ #[track_caller]
pub fn into_array_value(self) -> ArrayValue<'ctx> {
if let AnyValueEnum::ArrayValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ArrayValue variant", self)
+ panic!("Found {self:?} but expected the ArrayValue variant")
}
}
+ #[track_caller]
pub fn into_int_value(self) -> IntValue<'ctx> {
if let AnyValueEnum::IntValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the IntValue variant", self)
+ panic!("Found {self:?} but expected the IntValue variant")
}
}
+ #[track_caller]
pub fn into_float_value(self) -> FloatValue<'ctx> {
if let AnyValueEnum::FloatValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the FloatValue variant", self)
+ panic!("Found {self:?} but expected the FloatValue variant")
}
}
+ #[track_caller]
pub fn into_phi_value(self) -> PhiValue<'ctx> {
if let AnyValueEnum::PhiValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the PhiValue variant", self)
+ panic!("Found {self:?} but expected the PhiValue variant")
}
}
+ #[track_caller]
pub fn into_function_value(self) -> FunctionValue<'ctx> {
if let AnyValueEnum::FunctionValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the FunctionValue variant", self)
+ panic!("Found {self:?} but expected the FunctionValue variant")
}
}
+ #[track_caller]
pub fn into_pointer_value(self) -> PointerValue<'ctx> {
if let AnyValueEnum::PointerValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the PointerValue variant", self)
+ panic!("Found {self:?} but expected the PointerValue variant")
}
}
+ #[track_caller]
pub fn into_struct_value(self) -> StructValue<'ctx> {
if let AnyValueEnum::StructValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the StructValue variant", self)
+ panic!("Found {self:?} but expected the StructValue variant")
}
}
+ #[track_caller]
pub fn into_vector_value(self) -> VectorValue<'ctx> {
if let AnyValueEnum::VectorValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the VectorValue variant", self)
+ panic!("Found {self:?} but expected the VectorValue variant")
}
}
+ #[track_caller]
pub fn into_scalable_vector_value(self) -> ScalableVectorValue<'ctx> {
if let AnyValueEnum::ScalableVectorValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ScalableVectorValue variant", self)
+ panic!("Found {self:?} but expected the ScalableVectorValue variant")
}
}
+ #[track_caller]
pub fn into_instruction_value(self) -> InstructionValue<'ctx> {
if let AnyValueEnum::InstructionValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the InstructionValue variant", self)
+ panic!("Found {self:?} but expected the InstructionValue variant")
}
}
}
@@ -271,7 +283,9 @@ impl<'ctx> BasicValueEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMScalableVectorTypeKind => {
BasicValueEnum::ScalableVectorValue(ScalableVectorValue::new(value))
@@ -338,59 +352,66 @@ impl<'ctx> BasicValueEnum<'ctx> {
matches!(self, BasicValueEnum::ScalableVectorValue(_))
}
+ #[track_caller]
pub fn into_array_value(self) -> ArrayValue<'ctx> {
if let BasicValueEnum::ArrayValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ArrayValue variant", self)
+ panic!("Found {self:?} but expected the ArrayValue variant")
}
}
+ #[track_caller]
pub fn into_int_value(self) -> IntValue<'ctx> {
if let BasicValueEnum::IntValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the IntValue variant", self)
+ panic!("Found {self:?} but expected the IntValue variant")
}
}
+ #[track_caller]
pub fn into_float_value(self) -> FloatValue<'ctx> {
if let BasicValueEnum::FloatValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the FloatValue variant", self)
+ panic!("Found {self:?} but expected the FloatValue variant")
}
}
+ #[track_caller]
pub fn into_pointer_value(self) -> PointerValue<'ctx> {
if let BasicValueEnum::PointerValue(v) = self {
v
} else {
- panic!("Found {:?} but expected PointerValue variant", self)
+ panic!("Found {self:?} but expected PointerValue variant")
}
}
+ #[track_caller]
pub fn into_struct_value(self) -> StructValue<'ctx> {
if let BasicValueEnum::StructValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the StructValue variant", self)
+ panic!("Found {self:?} but expected the StructValue variant")
}
}
+ #[track_caller]
pub fn into_vector_value(self) -> VectorValue<'ctx> {
if let BasicValueEnum::VectorValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the VectorValue variant", self)
+ panic!("Found {self:?} but expected the VectorValue variant")
}
}
+ #[track_caller]
pub fn into_scalable_vector_value(self) -> ScalableVectorValue<'ctx> {
if let BasicValueEnum::ScalableVectorValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ScalableVectorValue variant", self)
+ panic!("Found {self:?} but expected the ScalableVectorValue variant")
}
}
}
@@ -417,19 +438,21 @@ impl<'ctx> AggregateValueEnum<'ctx> {
matches!(self, AggregateValueEnum::StructValue(_))
}
+ #[track_caller]
pub fn into_array_value(self) -> ArrayValue<'ctx> {
if let AggregateValueEnum::ArrayValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ArrayValue variant", self)
+ panic!("Found {self:?} but expected the ArrayValue variant")
}
}
+ #[track_caller]
pub fn into_struct_value(self) -> StructValue<'ctx> {
if let AggregateValueEnum::StructValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the StructValue variant", self)
+ panic!("Found {self:?} but expected the StructValue variant")
}
}
}
@@ -456,7 +479,9 @@ impl<'ctx> BasicMetadataValueEnum<'ctx> {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
LLVMTypeKind::LLVMScalableVectorTypeKind => {
BasicMetadataValueEnum::ScalableVectorValue(ScalableVectorValue::new(value))
@@ -498,67 +523,75 @@ impl<'ctx> BasicMetadataValueEnum<'ctx> {
matches!(self, BasicMetadataValueEnum::MetadataValue(_))
}
+ #[track_caller]
pub fn into_array_value(self) -> ArrayValue<'ctx> {
if let BasicMetadataValueEnum::ArrayValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ArrayValue variant", self)
+ panic!("Found {self:?} but expected the ArrayValue variant")
}
}
+ #[track_caller]
pub fn into_int_value(self) -> IntValue<'ctx> {
if let BasicMetadataValueEnum::IntValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the IntValue variant", self)
+ panic!("Found {self:?} but expected the IntValue variant")
}
}
+ #[track_caller]
pub fn into_float_value(self) -> FloatValue<'ctx> {
if let BasicMetadataValueEnum::FloatValue(v) = self {
v
} else {
- panic!("Found {:?} but expected FloatValue variant", self)
+ panic!("Found {self:?} but expected FloatValue variant")
}
}
+ #[track_caller]
pub fn into_pointer_value(self) -> PointerValue<'ctx> {
if let BasicMetadataValueEnum::PointerValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the PointerValue variant", self)
+ panic!("Found {self:?} but expected the PointerValue variant")
}
}
+ #[track_caller]
pub fn into_struct_value(self) -> StructValue<'ctx> {
if let BasicMetadataValueEnum::StructValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the StructValue variant", self)
+ panic!("Found {self:?} but expected the StructValue variant")
}
}
+ #[track_caller]
pub fn into_vector_value(self) -> VectorValue<'ctx> {
if let BasicMetadataValueEnum::VectorValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the VectorValue variant", self)
+ panic!("Found {self:?} but expected the VectorValue variant")
}
}
+ #[track_caller]
pub fn into_scalable_vector_value(self) -> ScalableVectorValue<'ctx> {
if let BasicMetadataValueEnum::ScalableVectorValue(v) = self {
v
} else {
- panic!("Found {:?} but expected the ScalableVectorValue variant", self)
+ panic!("Found {self:?} but expected the ScalableVectorValue variant")
}
}
+ #[track_caller]
pub fn into_metadata_value(self) -> MetadataValue<'ctx> {
if let BasicMetadataValueEnum::MetadataValue(v) = self {
v
} else {
- panic!("Found {:?} but expected MetaData variant", self)
+ panic!("Found {self:?} but expected MetaData variant")
}
}
}
diff --git a/src/values/float_value.rs b/src/values/float_value.rs
index ba396be5186..96eae6f904f 100644
--- a/src/values/float_value.rs
+++ b/src/values/float_value.rs
@@ -1,8 +1,10 @@
#[llvm_versions(..=17)]
use crate::types::IntType;
+#[llvm_versions(..=18)]
+use llvm_sys::core::LLVMConstFCmp;
#[llvm_versions(..=15)]
use llvm_sys::core::LLVMConstFNeg;
-use llvm_sys::core::{LLVMConstFCmp, LLVMConstRealGetDouble};
+use llvm_sys::core::LLVMConstRealGetDouble;
#[llvm_versions(..=17)]
use llvm_sys::core::{LLVMConstFPCast, LLVMConstFPExt, LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc};
use llvm_sys::prelude::LLVMValueRef;
@@ -15,8 +17,10 @@ use std::fmt::{self, Display};
use crate::types::AsTypeRef;
use crate::types::FloatType;
use crate::values::traits::AsValueRef;
-use crate::values::{InstructionValue, IntValue, Value};
-use crate::FloatPredicate;
+use crate::values::{InstructionValue, Value};
+
+#[llvm_versions(..=18)]
+use crate::{values::IntValue, FloatPredicate};
use super::AnyValue;
@@ -136,6 +140,7 @@ impl<'ctx> FloatValue<'ctx> {
}
// SubType: rhs same as lhs; return IntValue
+ #[llvm_versions(..=18)]
pub fn const_compare(self, op: FloatPredicate, rhs: FloatValue<'ctx>) -> IntValue<'ctx> {
unsafe { IntValue::new(LLVMConstFCmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) }
}
diff --git a/src/values/fn_value.rs b/src/values/fn_value.rs
index 00a5126f135..e93784ce9e1 100644
--- a/src/values/fn_value.rs
+++ b/src/values/fn_value.rs
@@ -10,7 +10,6 @@ use llvm_sys::core::{
LLVMIsAFunction, LLVMIsConstant, LLVMSetFunctionCallConv, LLVMSetGC, LLVMSetLinkage, LLVMSetParamAlignment,
};
use llvm_sys::core::{LLVMGetPersonalityFn, LLVMSetPersonalityFn};
-#[llvm_versions(7..)]
use llvm_sys::debuginfo::{LLVMGetSubprogram, LLVMSetSubprogram};
use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
@@ -21,7 +20,6 @@ use std::mem::forget;
use crate::attributes::{Attribute, AttributeLoc};
use crate::basic_block::BasicBlock;
-#[llvm_versions(7..)]
use crate::debug_info::DISubprogram;
use crate::module::Linkage;
use crate::support::to_c_str;
@@ -41,12 +39,10 @@ impl<'ctx> FunctionValue<'ctx> {
///
/// The ref must be valid and of type function.
pub unsafe fn new(value: LLVMValueRef) -> Option {
- if value.is_null() {
+ if value.is_null() || LLVMIsAFunction(value).is_null() {
return None;
}
- assert!(!LLVMIsAFunction(value).is_null());
-
Some(FunctionValue {
fn_value: Value::new(value),
})
@@ -207,16 +203,6 @@ impl<'ctx> FunctionValue<'ctx> {
LLVMDeleteFunction(self.as_value_ref())
}
- #[llvm_versions(..=7)]
- pub fn get_type(self) -> FunctionType<'ctx> {
- use crate::types::PointerType;
-
- let ptr_type = unsafe { PointerType::new(self.fn_value.get_type()) };
-
- ptr_type.get_element_type().into_function_type()
- }
-
- #[llvm_versions(8..)]
pub fn get_type(self) -> FunctionType<'ctx> {
unsafe { FunctionType::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) }
}
@@ -499,13 +485,11 @@ impl<'ctx> FunctionValue<'ctx> {
}
/// Set the debug info descriptor
- #[llvm_versions(7..)]
pub fn set_subprogram(self, subprogram: DISubprogram<'ctx>) {
unsafe { LLVMSetSubprogram(self.as_value_ref(), subprogram.metadata_ref) }
}
/// Get the debug info descriptor
- #[llvm_versions(7..)]
pub fn get_subprogram(self) -> Option> {
let metadata_ref = unsafe { LLVMGetSubprogram(self.as_value_ref()) };
diff --git a/src/values/generic_value.rs b/src/values/generic_value.rs
index f203e2ca128..6e60c259493 100644
--- a/src/values/generic_value.rs
+++ b/src/values/generic_value.rs
@@ -16,7 +16,7 @@ pub struct GenericValue<'ctx> {
}
impl<'ctx> GenericValue<'ctx> {
- pub(crate) unsafe fn new(generic_value: LLVMGenericValueRef) -> Self {
+ pub unsafe fn new(generic_value: LLVMGenericValueRef) -> Self {
assert!(!generic_value.is_null());
GenericValue {
diff --git a/src/values/global_value.rs b/src/values/global_value.rs
index 1ca9f5c1537..89d5482b680 100644
--- a/src/values/global_value.rs
+++ b/src/values/global_value.rs
@@ -1,14 +1,5 @@
-#[llvm_versions(8..)]
use llvm_sys::core::LLVMGlobalSetMetadata;
-#[llvm_versions(..=7)]
-use llvm_sys::core::{
- LLVMDeleteGlobal, LLVMGetAlignment, LLVMGetDLLStorageClass, LLVMGetInitializer, LLVMGetLinkage, LLVMGetNextGlobal,
- LLVMGetPreviousGlobal, LLVMGetSection, LLVMGetThreadLocalMode, LLVMGetVisibility, LLVMIsDeclaration,
- LLVMIsExternallyInitialized, LLVMIsGlobalConstant, LLVMIsThreadLocal, LLVMSetAlignment, LLVMSetDLLStorageClass,
- LLVMSetExternallyInitialized, LLVMSetGlobalConstant, LLVMSetInitializer, LLVMSetLinkage, LLVMSetSection,
- LLVMSetThreadLocal, LLVMSetThreadLocalMode, LLVMSetVisibility,
-};
-#[llvm_versions(8..)]
+
use llvm_sys::core::{
LLVMDeleteGlobal, LLVMGetAlignment, LLVMGetDLLStorageClass, LLVMGetInitializer, LLVMGetLinkage, LLVMGetNextGlobal,
LLVMGetPreviousGlobal, LLVMGetThreadLocalMode, LLVMGetVisibility, LLVMIsDeclaration, LLVMIsExternallyInitialized,
@@ -16,24 +7,21 @@ use llvm_sys::core::{
LLVMSetGlobalConstant, LLVMSetInitializer, LLVMSetLinkage, LLVMSetThreadLocal, LLVMSetThreadLocalMode,
LLVMSetVisibility,
};
-#[llvm_versions(7..)]
+
use llvm_sys::core::{LLVMGetUnnamedAddress, LLVMSetUnnamedAddress};
-#[llvm_versions(..=6)]
-use llvm_sys::core::{LLVMHasUnnamedAddr, LLVMSetUnnamedAddr};
use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::LLVMThreadLocalMode;
-#[llvm_versions(7..)]
+
use llvm_sys::LLVMUnnamedAddr;
use std::ffi::CStr;
use std::fmt::{self, Display};
-#[llvm_versions(7..)]
use crate::comdat::Comdat;
use crate::module::Linkage;
use crate::types::AnyTypeEnum;
use crate::values::traits::AsValueRef;
-#[llvm_versions(8..)]
+
use crate::values::MetadataValue;
use crate::values::{BasicValue, BasicValueEnum, PointerValue, Value};
use crate::{DLLStorageClass, GlobalVisibility, ThreadLocalMode};
@@ -167,22 +155,10 @@ impl<'ctx> GlobalValue<'ctx> {
unsafe { LLVMIsDeclaration(self.as_value_ref()) == 1 }
}
- #[llvm_versions(..=6)]
- pub fn has_unnamed_addr(self) -> bool {
- unsafe { LLVMHasUnnamedAddr(self.as_value_ref()) == 1 }
- }
-
- #[llvm_versions(7..)]
pub fn has_unnamed_addr(self) -> bool {
unsafe { LLVMGetUnnamedAddress(self.as_value_ref()) == LLVMUnnamedAddr::LLVMGlobalUnnamedAddr }
}
- #[llvm_versions(..=6)]
- pub fn set_unnamed_addr(self, has_unnamed_addr: bool) {
- unsafe { LLVMSetUnnamedAddr(self.as_value_ref(), has_unnamed_addr as i32) }
- }
-
- #[llvm_versions(7..)]
pub fn set_unnamed_addr(self, has_unnamed_addr: bool) {
unsafe {
if has_unnamed_addr {
@@ -246,13 +222,11 @@ impl<'ctx> GlobalValue<'ctx> {
}
/// Sets a metadata of the given type on the GlobalValue
- #[llvm_versions(8..)]
pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) {
unsafe { LLVMGlobalSetMetadata(self.as_value_ref(), kind_id, metadata.as_metadata_ref()) }
}
/// Gets a `Comdat` assigned to this `GlobalValue`, if any.
- #[llvm_versions(7..)]
pub fn get_comdat(self) -> Option {
use llvm_sys::comdat::LLVMGetComdat;
@@ -266,14 +240,12 @@ impl<'ctx> GlobalValue<'ctx> {
}
/// Assigns a `Comdat` to this `GlobalValue`.
- #[llvm_versions(7..)]
pub fn set_comdat(self, comdat: Comdat) {
use llvm_sys::comdat::LLVMSetComdat;
unsafe { LLVMSetComdat(self.as_value_ref(), comdat.0) }
}
- #[llvm_versions(7..)]
pub fn get_unnamed_address(self) -> UnnamedAddress {
use llvm_sys::core::LLVMGetUnnamedAddress;
@@ -282,7 +254,6 @@ impl<'ctx> GlobalValue<'ctx> {
UnnamedAddress::new(unnamed_address)
}
- #[llvm_versions(7..)]
pub fn set_unnamed_address(self, address: UnnamedAddress) {
use llvm_sys::core::LLVMSetUnnamedAddress;
@@ -297,7 +268,6 @@ impl<'ctx> GlobalValue<'ctx> {
unsafe { LLVMSetLinkage(self.as_value_ref(), linkage.into()) }
}
- #[llvm_versions(8..)]
pub fn get_value_type(self) -> AnyTypeEnum<'ctx> {
unsafe { AnyTypeEnum::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) }
}
@@ -316,7 +286,7 @@ impl Display for GlobalValue<'_> {
}
/// This enum determines the significance of a `GlobalValue`'s address.
-#[llvm_versions(7..)]
+
#[llvm_enum(LLVMUnnamedAddr)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UnnamedAddress {
diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs
index 1de4cc206ea..c100ccfa49f 100644
--- a/src/values/instruction_value.rs
+++ b/src/values/instruction_value.rs
@@ -5,28 +5,87 @@ use either::{
#[llvm_versions(14..)]
use llvm_sys::core::LLVMGetGEPSourceElementType;
use llvm_sys::core::{
- LLVMGetAlignment, LLVMGetAllocatedType, LLVMGetFCmpPredicate, LLVMGetICmpPredicate, LLVMGetInstructionOpcode,
- LLVMGetInstructionParent, LLVMGetMetadata, LLVMGetNextInstruction, LLVMGetNumOperands, LLVMGetOperand,
- LLVMGetOperandUse, LLVMGetPreviousInstruction, LLVMGetVolatile, LLVMHasMetadata, LLVMInstructionClone,
- LLVMInstructionEraseFromParent, LLVMInstructionRemoveFromParent, LLVMIsAAllocaInst, LLVMIsABasicBlock,
- LLVMIsAGetElementPtrInst, LLVMIsALoadInst, LLVMIsAStoreInst, LLVMIsATerminatorInst, LLVMIsConditional,
- LLVMIsTailCall, LLVMSetAlignment, LLVMSetMetadata, LLVMSetOperand, LLVMSetVolatile, LLVMValueAsBasicBlock,
+ LLVMGetAlignment, LLVMGetAllocatedType, LLVMGetFCmpPredicate, LLVMGetICmpPredicate, LLVMGetIndices,
+ LLVMGetInstructionOpcode, LLVMGetInstructionParent, LLVMGetMetadata, LLVMGetNextInstruction, LLVMGetNumIndices,
+ LLVMGetNumOperands, LLVMGetOperand, LLVMGetOperandUse, LLVMGetPreviousInstruction, LLVMGetVolatile,
+ LLVMHasMetadata, LLVMInstructionClone, LLVMInstructionEraseFromParent, LLVMInstructionRemoveFromParent,
+ LLVMIsAAllocaInst, LLVMIsABasicBlock, LLVMIsAGetElementPtrInst, LLVMIsALoadInst, LLVMIsAStoreInst,
+ LLVMIsATerminatorInst, LLVMIsConditional, LLVMIsTailCall, LLVMSetAlignment, LLVMSetMetadata, LLVMSetOperand,
+ LLVMSetVolatile, LLVMValueAsBasicBlock,
};
-use llvm_sys::core::{LLVMGetOrdering, LLVMSetOrdering};
#[llvm_versions(10..)]
-use llvm_sys::core::{LLVMIsAAtomicCmpXchgInst, LLVMIsAAtomicRMWInst};
+use llvm_sys::core::{LLVMGetAtomicRMWBinOp, LLVMIsAAtomicCmpXchgInst, LLVMIsAAtomicRMWInst};
+use llvm_sys::core::{LLVMGetOrdering, LLVMSetOrdering};
use llvm_sys::prelude::LLVMValueRef;
use llvm_sys::LLVMOpcode;
use std::{ffi::CStr, fmt, fmt::Display};
+use crate::error::AlignmentError;
use crate::values::{BasicValue, BasicValueEnum, BasicValueUse, MetadataValue, Value};
+#[llvm_versions(10..)]
+use crate::AtomicRMWBinOp;
use crate::{basic_block::BasicBlock, types::AnyTypeEnum};
use crate::{types::BasicTypeEnum, values::traits::AsValueRef};
use crate::{AtomicOrdering, FloatPredicate, IntPredicate};
use super::AnyValue;
+/// Errors for atomic operations on load/store instructions.
+#[derive(Debug, thiserror::Error, PartialEq, Eq)]
+pub enum AtomicError {
+ #[error("The release ordering is not valid on load instructions.")]
+ ReleaseOnLoad,
+ #[error("The acq_rel ordering is not valid on load or store instructions.")]
+ AcquireRelease,
+ #[error("The acquire ordering is not valid on store instructions.")]
+ AcquireOnStore,
+}
+
+/// Errors for InstructionValue.
+#[llvm_versions(..=9)]
+#[derive(Debug, thiserror::Error, PartialEq, Eq)]
+pub enum InstructionValueError {
+ #[error("Cannot set name of a void-type instruction.")]
+ CannotNameVoidTypeInst,
+ #[error("Value is not a load or store instruction.")]
+ NotMemoryAccessInst,
+ #[error("Value is not a load or store instruction.")]
+ NotLoadOrStoreInst,
+ #[error("Value is not an alloca instruction.")]
+ NotAllocaInst,
+ #[error("Alignment Error: {0}")]
+ AlignmentError(AlignmentError),
+ #[error("Not a GEP instruction.")]
+ NotGEPInst,
+ #[error("Atomic Error: {0}")]
+ AtomicError(#[from] AtomicError),
+ #[error("Metadata is expected to be a node.")]
+ ExpectedNode,
+}
+
+/// Errors for InstructionValue.
+#[llvm_versions(10..)]
+#[derive(Debug, thiserror::Error, PartialEq, Eq)]
+pub enum InstructionValueError {
+ #[error("Cannot set name of a void-type instruction.")]
+ CannotNameVoidTypeInst,
+ #[error("Value is not a load, store, atomicrmw or cmpxchg instruction.")]
+ NotMemoryAccessInst,
+ #[error("Value is not a load or store instruction.")]
+ NotLoadOrStoreInst,
+ #[error("Value is not an alloca instruction.")]
+ NotAllocaInst,
+ #[error("Alignment Error: {0}")]
+ AlignmentError(AlignmentError),
+ #[error("Not a GEP instruction.")]
+ NotGEPInst,
+ #[error("Atomic Error: {0}")]
+ AtomicError(AtomicError),
+ #[error("Metadata is expected to be a node.")]
+ ExpectedNode,
+}
+
// REVIEW: Split up into structs for SubTypes on InstructionValues?
// REVIEW: This should maybe be split up into InstructionOpcode and ConstOpcode?
// see LLVMGetConstOpcode
@@ -53,7 +112,6 @@ pub enum InstructionOpcode {
CleanupRet,
ExtractElement,
ExtractValue,
- #[llvm_versions(8..)]
FNeg,
FAdd,
FCmp,
@@ -123,6 +181,7 @@ impl<'ctx> InstructionValue<'ctx> {
fn is_a_alloca_inst(self) -> bool {
!unsafe { LLVMIsAAllocaInst(self.as_value_ref()) }.is_null()
}
+ #[allow(dead_code)]
fn is_a_getelementptr_inst(self) -> bool {
!unsafe { LLVMIsAGetElementPtrInst(self.as_value_ref()) }.is_null()
}
@@ -175,13 +234,13 @@ impl<'ctx> InstructionValue<'ctx> {
return Some(*self);
}
}
- return self.get_next_instruction()?.get_instruction_with_name(name);
+ self.get_next_instruction()?.get_instruction_with_name(name)
}
/// Set name of the `InstructionValue`.
- pub fn set_name(&self, name: &str) -> Result<(), &'static str> {
+ pub fn set_name(&self, name: &str) -> Result<(), InstructionValueError> {
if self.get_type().is_void_type() {
- Err("Cannot set name of a void-type instruction!")
+ Err(InstructionValueError::CannotNameVoidTypeInst)
} else {
self.instruction_value.set_name(name);
Ok(())
@@ -246,7 +305,7 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to terminators
/// Returns if a terminator is conditional or not
pub fn is_conditional(self) -> bool {
- if self.is_terminator() {
+ if self.get_opcode() == InstructionOpcode::Br {
unsafe { LLVMIsConditional(self.as_value_ref()) == 1 }
} else {
false
@@ -350,11 +409,11 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to memory access instructions
/// Returns whether or not a memory access instruction is volatile.
#[llvm_versions(..=9)]
- pub fn get_volatile(self) -> Result {
+ pub fn get_volatile(self) -> Result {
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
// does not export that functionality until 10.0.
if !self.is_a_load_inst() && !self.is_a_store_inst() {
- return Err("Value is not a load or store.");
+ return Err(InstructionValueError::NotMemoryAccessInst);
}
Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
}
@@ -362,10 +421,10 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to memory access instructions
/// Returns whether or not a memory access instruction is volatile.
#[llvm_versions(10..)]
- pub fn get_volatile(self) -> Result {
+ pub fn get_volatile(self) -> Result {
if !self.is_a_load_inst() && !self.is_a_store_inst() && !self.is_a_atomicrmw_inst() && !self.is_a_cmpxchg_inst()
{
- return Err("Value is not a load, store, atomicrmw or cmpxchg.");
+ return Err(InstructionValueError::NotMemoryAccessInst);
}
Ok(unsafe { LLVMGetVolatile(self.as_value_ref()) } == 1)
}
@@ -373,22 +432,23 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to memory access instructions
/// Sets whether or not a memory access instruction is volatile.
#[llvm_versions(..=9)]
- pub fn set_volatile(self, volatile: bool) -> Result<(), &'static str> {
+ pub fn set_volatile(self, volatile: bool) -> Result<(), InstructionValueError> {
// Although cmpxchg and atomicrmw can have volatile, LLVM's C API
// does not export that functionality until 10.0.
if !self.is_a_load_inst() && !self.is_a_store_inst() {
- return Err("Value is not a load or store.");
+ return Err(InstructionValueError::NotMemoryAccessInst);
}
- Ok(unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) })
+ unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) };
+ Ok(())
}
// SubTypes: Only apply to memory access instructions
/// Sets whether or not a memory access instruction is volatile.
#[llvm_versions(10..)]
- pub fn set_volatile(self, volatile: bool) -> Result<(), &'static str> {
+ pub fn set_volatile(self, volatile: bool) -> Result<(), InstructionValueError> {
if !self.is_a_load_inst() && !self.is_a_store_inst() && !self.is_a_atomicrmw_inst() && !self.is_a_cmpxchg_inst()
{
- return Err("Value is not a load, store, atomicrmw or cmpxchg.");
+ return Err(InstructionValueError::NotMemoryAccessInst);
}
unsafe { LLVMSetVolatile(self.as_value_ref(), volatile as i32) };
Ok(())
@@ -396,9 +456,9 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to alloca instruction
/// Returns the type that is allocated by the alloca instruction.
- pub fn get_allocated_type(self) -> Result, &'static str> {
+ pub fn get_allocated_type(self) -> Result, InstructionValueError> {
if !self.is_a_alloca_inst() {
- return Err("Value is not an alloca.");
+ return Err(InstructionValueError::NotAllocaInst);
}
Ok(unsafe { BasicTypeEnum::new(LLVMGetAllocatedType(self.as_value_ref())) })
}
@@ -406,37 +466,37 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to GetElementPtr instruction
/// Returns the source element type of the given GEP.
#[llvm_versions(14..)]
- pub fn get_gep_source_element_type(self) -> Result, &'static str> {
+ pub fn get_gep_source_element_type(self) -> Result, InstructionValueError> {
if !self.is_a_getelementptr_inst() {
- return Err("Value is not a GEP.");
+ return Err(InstructionValueError::NotGEPInst);
}
Ok(unsafe { BasicTypeEnum::new(LLVMGetGEPSourceElementType(self.as_value_ref())) })
}
// SubTypes: Only apply to memory access and alloca instructions
/// Returns alignment on a memory access instruction or alloca.
- pub fn get_alignment(self) -> Result {
+ pub fn get_alignment(self) -> Result {
if !self.is_a_alloca_inst() && !self.is_a_load_inst() && !self.is_a_store_inst() {
- return Err("Value is not an alloca, load or store.");
+ return Err(InstructionValueError::AlignmentError(
+ AlignmentError::UnalignedInstruction,
+ ));
}
Ok(unsafe { LLVMGetAlignment(self.as_value_ref()) })
}
// SubTypes: Only apply to memory access and alloca instructions
/// Sets alignment on a memory access instruction or alloca.
- pub fn set_alignment(self, alignment: u32) -> Result<(), &'static str> {
- #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
- {
- if alignment == 0 {
- return Err("Alignment cannot be 0");
- }
- }
- //The alignment = 0 check above covers LLVM >= 11, the != 0 check here keeps older versions compatible
- if !alignment.is_power_of_two() && alignment != 0 {
- return Err("Alignment is not a power of 2!");
+ pub fn set_alignment(self, alignment: u32) -> Result<(), InstructionValueError> {
+ // Zero check is unnecessary as 0 is not a power of two.
+ if !alignment.is_power_of_two() {
+ return Err(InstructionValueError::AlignmentError(AlignmentError::NonPowerOfTwo(
+ alignment,
+ )));
}
if !self.is_a_alloca_inst() && !self.is_a_load_inst() && !self.is_a_store_inst() {
- return Err("Value is not an alloca, load or store.");
+ return Err(InstructionValueError::AlignmentError(
+ AlignmentError::UnalignedInstruction,
+ ));
}
unsafe { LLVMSetAlignment(self.as_value_ref(), alignment) };
Ok(())
@@ -444,31 +504,31 @@ impl<'ctx> InstructionValue<'ctx> {
// SubTypes: Only apply to memory access instructions
/// Returns atomic ordering on a memory access instruction.
- pub fn get_atomic_ordering(self) -> Result {
+ pub fn get_atomic_ordering(self) -> Result {
if !self.is_a_load_inst() && !self.is_a_store_inst() {
- return Err("Value is not a load or store.");
+ return Err(InstructionValueError::NotLoadOrStoreInst);
}
Ok(unsafe { LLVMGetOrdering(self.as_value_ref()) }.into())
}
// SubTypes: Only apply to memory access instructions
/// Sets atomic ordering on a memory access instruction.
- pub fn set_atomic_ordering(self, ordering: AtomicOrdering) -> Result<(), &'static str> {
+ pub fn set_atomic_ordering(self, ordering: AtomicOrdering) -> Result<(), InstructionValueError> {
// Although fence and atomicrmw both have an ordering, the LLVM C API
// does not support them. The cmpxchg instruction has two orderings and
// does not work with this API.
if !self.is_a_load_inst() && !self.is_a_store_inst() {
- return Err("Value is not a load or store instruction.");
+ return Err(InstructionValueError::NotLoadOrStoreInst);
}
match ordering {
AtomicOrdering::Release if self.is_a_load_inst() => {
- return Err("The release ordering is not valid on load instructions.")
+ return Err(InstructionValueError::AtomicError(AtomicError::ReleaseOnLoad))
},
AtomicOrdering::AcquireRelease => {
- return Err("The acq_rel ordering is not valid on load or store instructions.")
+ return Err(InstructionValueError::AtomicError(AtomicError::AcquireRelease))
},
AtomicOrdering::Acquire if self.is_a_store_inst() => {
- return Err("The acquire ordering is not valid on store instructions.")
+ return Err(InstructionValueError::AtomicError(AtomicError::AcquireOnStore))
},
_ => {},
};
@@ -490,9 +550,9 @@ impl<'ctx> InstructionValue<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -534,7 +594,7 @@ impl<'ctx> InstructionValue<'ctx> {
/// 2) Bitcast has one: a variable float pointer %0
/// 3) Function call has two: i8 pointer %1 argument, and the free function itself
/// 4) Void return has zero: void is not a value and does not count as an operand
- /// even though the return instruction can take values.
+ /// even though the return instruction can take values.
pub fn get_num_operands(self) -> u32 {
unsafe { LLVMGetNumOperands(self.as_value_ref()) as u32 }
}
@@ -553,9 +613,9 @@ impl<'ctx> InstructionValue<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -602,7 +662,7 @@ impl<'ctx> InstructionValue<'ctx> {
/// 2) Bitcast has one: a variable float pointer %0
/// 3) Function call has two: i8 pointer %1 argument, and the free function itself
/// 4) Void return has zero: void is not a value and does not count as an operand
- /// even though the return instruction can take values.
+ /// even though the return instruction can take values.
pub fn get_operand(self, index: u32) -> Option, BasicBlock<'ctx>>> {
let num_operands = self.get_num_operands();
@@ -657,9 +717,9 @@ impl<'ctx> InstructionValue<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -703,9 +763,9 @@ impl<'ctx> InstructionValue<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -756,6 +816,88 @@ impl<'ctx> InstructionValue<'ctx> {
}
}
+ /// Obtains the number of indices an `InstructionValue` has.
+ /// An index is used in `ExtractValue` and `InsertValue` instructions to specify
+ /// which field or element to access in an aggregate type (struct or array).
+ ///
+ /// Returns 0 for instructions that are not `ExtractValue` or `InsertValue`.
+ ///
+ /// The following example,
+ ///
+ /// ```no_run
+ /// use inkwell::context::Context;
+ /// use inkwell::values::BasicValue;
+ ///
+ /// let context = Context::create();
+ /// let module = context.create_module("ivs");
+ /// let builder = context.create_builder();
+ /// let void_type = context.void_type();
+ /// let i32_type = context.i32_type();
+ /// let struct_type = context.struct_type(&[i32_type.into(), i32_type.into()], false);
+ /// let fn_type = void_type.fn_type(&[], false);
+ ///
+ /// let function = module.add_function("test", fn_type, None);
+ /// let basic_block = context.append_basic_block(function, "entry");
+ ///
+ /// builder.position_at_end(basic_block);
+ ///
+ /// let struct_val = struct_type.get_undef();
+ /// let extract_instruction = builder.build_extract_value(struct_val, 0, "extract").unwrap()
+ /// .as_instruction_value().unwrap();
+ ///
+ /// assert_eq!(extract_instruction.get_num_indices(), 1);
+ /// ```
+ pub fn get_num_indices(self) -> u32 {
+ let opcode = self.get_opcode();
+ if opcode != InstructionOpcode::ExtractValue && opcode != InstructionOpcode::InsertValue {
+ return 0;
+ }
+ unsafe { LLVMGetNumIndices(self.as_value_ref()) }
+ }
+
+ /// Obtains the indices an `InstructionValue` has as a vector.
+ /// An index is used in `ExtractValue` and `InsertValue` instructions to specify
+ /// which field or element to access in an aggregate type (struct or array).
+ ///
+ /// Returns an empty vector for instructions that are not `ExtractValue` or `InsertValue`.
+ ///
+ /// The following example,
+ ///
+ /// ```no_run
+ /// use inkwell::context::Context;
+ /// use inkwell::values::BasicValue;
+ ///
+ /// let context = Context::create();
+ /// let module = context.create_module("ivs");
+ /// let builder = context.create_builder();
+ /// let void_type = context.void_type();
+ /// let i32_type = context.i32_type();
+ /// let struct_type = context.struct_type(&[i32_type.into(), i32_type.into()], false);
+ /// let fn_type = void_type.fn_type(&[], false);
+ ///
+ /// let function = module.add_function("test", fn_type, None);
+ /// let basic_block = context.append_basic_block(function, "entry");
+ ///
+ /// builder.position_at_end(basic_block);
+ ///
+ /// let struct_val = struct_type.get_undef();
+ /// let extract_instruction = builder.build_extract_value(struct_val, 0, "extract").unwrap()
+ /// .as_instruction_value().unwrap();
+ ///
+ /// assert_eq!(extract_instruction.get_indices(), vec![0]);
+ /// ```
+ pub fn get_indices(self) -> Vec {
+ let num_indices = self.get_num_indices();
+ if num_indices == 0 {
+ return Vec::new();
+ }
+
+ unsafe {
+ let indices_ptr = LLVMGetIndices(self.as_value_ref());
+ std::slice::from_raw_parts(indices_ptr, num_indices as usize).to_vec()
+ }
+ }
+
/// Gets the first use of an `InstructionValue` if any.
///
/// The following example,
@@ -770,9 +912,9 @@ impl<'ctx> InstructionValue<'ctx> {
/// let builder = context.create_builder();
/// let void_type = context.void_type();
/// let f32_type = context.f32_type();
- /// #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ /// #[cfg(feature = "typed-pointers")]
/// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- /// #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
+ /// #[cfg(not(feature = "typed-pointers"))]
/// let f32_ptr_type = context.ptr_type(AddressSpace::default());
/// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
///
@@ -829,6 +971,22 @@ impl<'ctx> InstructionValue<'ctx> {
}
}
+ /// Gets the binary operation of an `AtomicRMW` `InstructionValue`.
+ /// For instance, in the LLVM instruction
+ /// `%3 = atomicrmw add i32* %ptr, i32 %val monotonic`
+ /// this gives the `add`.
+ ///
+ /// If the instruction is not an `AtomicRMW`, this returns None.
+ #[llvm_versions(10..)]
+ pub fn get_atomic_rmw_bin_op(self) -> Option {
+ if self.get_opcode() == InstructionOpcode::AtomicRMW {
+ let bin_op = unsafe { LLVMGetAtomicRMWBinOp(self.as_value_ref()) };
+ Some(AtomicRMWBinOp::new(bin_op))
+ } else {
+ None
+ }
+ }
+
/// Determines whether or not this `Instruction` has any associated metadata.
pub fn has_metadata(self) -> bool {
unsafe { LLVMHasMetadata(self.instruction_value.value) == 1 }
@@ -848,9 +1006,9 @@ impl<'ctx> InstructionValue<'ctx> {
/// Determines whether or not this `Instruction` has any associated metadata
/// `kind_id`.
- pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) -> Result<(), &'static str> {
+ pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) -> Result<(), InstructionValueError> {
if !metadata.is_node() {
- return Err("metadata is expected to be a node.");
+ return Err(InstructionValueError::ExpectedNode);
}
unsafe {
diff --git a/src/values/int_value.rs b/src/values/int_value.rs
index 145a777e951..14877f28cbc 100644
--- a/src/values/int_value.rs
+++ b/src/values/int_value.rs
@@ -1,16 +1,23 @@
-#[llvm_versions(..=16)]
-use llvm_sys::core::LLVMConstSelect;
#[llvm_versions(..=17)]
use llvm_sys::core::{
LLVMConstAShr, LLVMConstAnd, LLVMConstIntCast, LLVMConstLShr, LLVMConstOr, LLVMConstSExt, LLVMConstSExtOrBitCast,
LLVMConstSIToFP, LLVMConstUIToFP, LLVMConstZExt, LLVMConstZExtOrBitCast,
};
use llvm_sys::core::{
- LLVMConstAdd, LLVMConstBitCast, LLVMConstICmp, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue,
- LLVMConstIntToPtr, LLVMConstMul, LLVMConstNSWAdd, LLVMConstNSWMul, LLVMConstNSWNeg, LLVMConstNSWSub,
- LLVMConstNUWAdd, LLVMConstNUWMul, LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstShl,
- LLVMConstSub, LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstXor, LLVMIsAConstantInt,
+ LLVMConstAdd, LLVMConstBitCast, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr,
+ LLVMConstMul, LLVMConstNSWAdd, LLVMConstNSWMul, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWMul,
+ LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstSub, LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstXor,
+ LLVMIsAConstantInt,
};
+#[llvm_versions(..=16)]
+use llvm_sys::core::{LLVMConstNUWNeg, LLVMConstSelect};
+
+#[llvm_versions(17..)]
+use llvm_sys::core::LLVMSetNUW;
+
+#[llvm_versions(..=18)]
+use llvm_sys::core::{LLVMConstICmp, LLVMConstShl};
+
use llvm_sys::prelude::LLVMValueRef;
use std::convert::TryFrom;
@@ -26,6 +33,8 @@ use crate::values::FloatValue;
#[llvm_versions(..=16)]
use crate::values::{BasicValue, BasicValueEnum};
use crate::values::{InstructionValue, PointerValue, Value};
+
+#[llvm_versions(..=18)]
use crate::IntPredicate;
use super::AnyValue;
@@ -93,10 +102,20 @@ impl<'ctx> IntValue<'ctx> {
unsafe { IntValue::new(LLVMConstNSWNeg(self.as_value_ref())) }
}
+ #[llvm_versions(..17)]
pub fn const_nuw_neg(self) -> Self {
unsafe { IntValue::new(LLVMConstNUWNeg(self.as_value_ref())) }
}
+ #[llvm_versions(17..)]
+ pub fn const_nuw_neg(self) -> Self {
+ let value = unsafe { LLVMConstNeg(self.as_value_ref()) };
+ unsafe {
+ LLVMSetNUW(value, true.into());
+ }
+ unsafe { IntValue::new(value) }
+ }
+
pub fn const_add(self, rhs: IntValue<'ctx>) -> Self {
unsafe { IntValue::new(LLVMConstAdd(self.as_value_ref(), rhs.as_value_ref())) }
}
@@ -202,6 +221,7 @@ impl<'ctx> IntValue<'ctx> {
}
// TODO: Give shift methods more descriptive names
+ #[llvm_versions(..=18)]
pub fn const_shl(self, rhs: IntValue<'ctx>) -> Self {
unsafe { IntValue::new(LLVMConstShl(self.as_value_ref(), rhs.as_value_ref())) }
}
@@ -269,6 +289,7 @@ impl<'ctx> IntValue<'ctx> {
}
// SubType: rhs same as lhs; return IntValue
+ #[llvm_versions(..=18)]
pub fn const_int_compare(self, op: IntPredicate, rhs: IntValue<'ctx>) -> IntValue<'ctx> {
unsafe { IntValue::new(LLVMConstICmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) }
}
diff --git a/src/values/metadata_value.rs b/src/values/metadata_value.rs
index 4a56c36c3f9..2db3d5d050e 100644
--- a/src/values/metadata_value.rs
+++ b/src/values/metadata_value.rs
@@ -3,9 +3,7 @@ use llvm_sys::core::{
};
use llvm_sys::prelude::LLVMValueRef;
-#[llvm_versions(7..)]
use llvm_sys::core::LLVMValueAsMetadata;
-#[llvm_versions(7..)]
use llvm_sys::prelude::LLVMMetadataRef;
use crate::values::traits::AsValueRef;
@@ -20,13 +18,7 @@ use std::fmt::{self, Display};
/// for the first input string that isn't known.
///
/// Each LLVM version has a different set of pre-defined metadata kinds.
-pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = if cfg!(feature = "llvm4-0") {
- 22
-} else if cfg!(feature = "llvm5-0") {
- 23
-} else if cfg!(any(feature = "llvm6-0", feature = "llvm7-0")) {
- 25
-} else if cfg!(feature = "llvm8-0") {
+pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = if cfg!(feature = "llvm8-0") {
26
} else if cfg!(feature = "llvm9-0") {
28
@@ -38,8 +30,12 @@ pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = if cfg!(feature = "llvm4-0") {
36
} else if cfg!(any(feature = "llvm16-0", feature = "llvm17-0")) {
39
-} else if cfg!(feature = "llvm18-0") {
+} else if cfg!(feature = "llvm18-1") {
40
+} else if cfg!(feature = "llvm19-1") {
+ 41
+} else if cfg!(feature = "llvm20-1") {
+ 42
} else {
panic!("Unhandled LLVM version")
};
@@ -64,7 +60,6 @@ impl<'ctx> MetadataValue<'ctx> {
}
}
- #[llvm_versions(7..)]
pub(crate) fn as_metadata_ref(self) -> LLVMMetadataRef {
unsafe { LLVMValueAsMetadata(self.as_value_ref()) }
}
diff --git a/src/values/mod.rs b/src/values/mod.rs
index 04d3ac54a6c..69574b60c2e 100644
--- a/src/values/mod.rs
+++ b/src/values/mod.rs
@@ -21,14 +21,16 @@ mod struct_value;
mod traits;
mod vec_value;
-#[cfg(feature = "llvm18-0")]
+#[cfg(any(feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1"))]
pub(crate) mod operand_bundle;
#[cfg(not(any(
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
)))]
mod callable_value;
@@ -36,7 +38,9 @@ mod callable_value;
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
)))]
pub use crate::values::callable_value::CallableValue;
@@ -52,9 +56,11 @@ pub use crate::values::float_value::FloatValue;
pub use crate::values::fn_value::FunctionValue;
pub use crate::values::generic_value::GenericValue;
pub use crate::values::global_value::GlobalValue;
-#[llvm_versions(7..)]
+
pub use crate::values::global_value::UnnamedAddress;
-pub use crate::values::instruction_value::{InstructionOpcode, InstructionValue, OperandIter, OperandUseIter};
+pub use crate::values::instruction_value::{
+ AtomicError, InstructionOpcode, InstructionValue, InstructionValueError, OperandIter, OperandUseIter,
+};
pub use crate::values::int_value::IntValue;
pub use crate::values::metadata_value::{MetadataValue, FIRST_CUSTOM_METADATA_KIND_ID};
pub use crate::values::phi_value::IncomingIter;
@@ -73,8 +79,9 @@ pub use crate::values::vec_value::VectorValue;
pub use llvm_sys::LLVMTailCallKind;
use llvm_sys::core::{
- LLVMDumpValue, LLVMGetFirstUse, LLVMGetSection, LLVMIsAInstruction, LLVMIsConstant, LLVMIsNull, LLVMIsUndef,
- LLVMPrintTypeToString, LLVMPrintValueToString, LLVMReplaceAllUsesWith, LLVMSetSection, LLVMTypeOf,
+ LLVMDumpValue, LLVMGetFirstUse, LLVMGetSection, LLVMGetValueName2, LLVMIsAInstruction, LLVMIsConstant, LLVMIsNull,
+ LLVMIsUndef, LLVMPrintTypeToString, LLVMPrintValueToString, LLVMReplaceAllUsesWith, LLVMSetSection,
+ LLVMSetValueName2, LLVMTypeOf,
};
use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};
@@ -89,7 +96,7 @@ struct Value<'ctx> {
}
impl<'ctx> Value<'ctx> {
- pub(crate) unsafe fn new(value: LLVMValueRef) -> Self {
+ pub unsafe fn new(value: LLVMValueRef) -> Self {
debug_assert!(
!value.is_null(),
"This should never happen since containing struct should check null ptrs"
@@ -130,34 +137,13 @@ impl<'ctx> Value<'ctx> {
fn set_name(self, name: &str) {
let c_string = to_c_str(name);
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
- {
- use llvm_sys::core::LLVMSetValueName;
-
- unsafe {
- LLVMSetValueName(self.value, c_string.as_ptr());
- }
- }
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- use llvm_sys::core::LLVMSetValueName2;
-
- unsafe { LLVMSetValueName2(self.value, c_string.as_ptr(), c_string.to_bytes().len()) }
- }
+ unsafe { LLVMSetValueName2(self.value, c_string.as_ptr(), c_string.to_bytes().len()) }
}
// get_name should *not* return a LLVMString, because it is not an owned value AFAICT
// TODO: Should make this take ownership of self. But what is the lifetime of the string? 'ctx?
fn get_name(&self) -> &CStr {
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0"))]
- let ptr = unsafe {
- use llvm_sys::core::LLVMGetValueName;
-
- LLVMGetValueName(self.value)
- };
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
let ptr = unsafe {
- use llvm_sys::core::LLVMGetValueName2;
let mut len = 0;
LLVMGetValueName2(self.value, &mut len)
diff --git a/src/values/ptr_value.rs b/src/values/ptr_value.rs
index 97726f88629..9efabaa591e 100644
--- a/src/values/ptr_value.rs
+++ b/src/values/ptr_value.rs
@@ -1,6 +1,7 @@
-#[llvm_versions(..=14)]
+#[cfg(all(feature = "typed-pointers", not(feature = "llvm16-0")))]
+#[allow(deprecated)]
use llvm_sys::core::{LLVMConstGEP, LLVMConstInBoundsGEP};
-#[llvm_versions(15..)]
+#[cfg(any(not(feature = "typed-pointers"), feature = "llvm16-0"))]
use llvm_sys::core::{LLVMConstGEP2, LLVMConstInBoundsGEP2};
use llvm_sys::core::{LLVMConstAddrSpaceCast, LLVMConstPointerCast, LLVMConstPtrToInt};
@@ -10,7 +11,9 @@ use std::convert::TryFrom;
use std::ffi::CStr;
use std::fmt::{self, Display};
-use crate::types::{AsTypeRef, BasicType, IntType, PointerType};
+#[cfg(not(feature = "typed-pointers"))]
+use crate::types::BasicType;
+use crate::types::{AsTypeRef, IntType, PointerType};
use crate::values::{AsValueRef, InstructionValue, IntValue, Value};
use super::AnyValue;
@@ -82,10 +85,12 @@ impl<'ctx> PointerValue<'ctx> {
// REVIEW: Should this be on array value too?
/// 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.
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub unsafe fn const_gep(self, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> {
let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = {
LLVMConstGEP(
self.as_value_ref(),
@@ -93,13 +98,22 @@ impl<'ctx> PointerValue<'ctx> {
index_values.len() as u32,
)
};
+ #[cfg(feature = "llvm16-0")]
+ let value = {
+ LLVMConstGEP2(
+ self.get_type().get_element_type().as_type_ref(),
+ self.as_value_ref(),
+ index_values.as_mut_ptr(),
+ index_values.len() as u32,
+ )
+ };
PointerValue::new(value)
}
// REVIEW: Should this be on array value too?
/// 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.
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub unsafe fn const_gep>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> {
let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
@@ -116,10 +130,12 @@ impl<'ctx> PointerValue<'ctx> {
}
/// 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.
- #[llvm_versions(..=14)]
+ #[cfg(feature = "typed-pointers")]
pub unsafe fn const_in_bounds_gep(self, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> {
let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect();
+ #[cfg(not(feature = "llvm16-0"))]
+ #[allow(deprecated)]
let value = {
LLVMConstInBoundsGEP(
self.as_value_ref(),
@@ -127,12 +143,21 @@ impl<'ctx> PointerValue<'ctx> {
index_values.len() as u32,
)
};
+ #[cfg(feature = "llvm16-0")]
+ let value = {
+ LLVMConstInBoundsGEP2(
+ self.get_type().get_element_type().as_type_ref(),
+ self.as_value_ref(),
+ index_values.as_mut_ptr(),
+ index_values.len() as u32,
+ )
+ };
PointerValue::new(value)
}
/// 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.
- #[llvm_versions(15..)]
+ #[cfg(not(feature = "typed-pointers"))]
pub unsafe fn const_in_bounds_gep>(
self,
ty: T,
diff --git a/src/values/traits.rs b/src/values/traits.rs
index 760a30cbf71..9555477a385 100644
--- a/src/values/traits.rs
+++ b/src/values/traits.rs
@@ -122,7 +122,7 @@ pub unsafe trait BasicValue<'ctx>: AnyValue<'ctx> {
unsafe { Some(InstructionValue::new(self.as_value_ref())) }
}
- fn get_first_use(&self) -> Option {
+ fn get_first_use(&self) -> Option> {
unsafe { Value::new(self.as_value_ref()).get_first_use() }
}
diff --git a/tests/all/main.rs b/tests/all/main.rs
index 2f57a23914c..a9b0027854c 100644
--- a/tests/all/main.rs
+++ b/tests/all/main.rs
@@ -7,15 +7,20 @@ mod test_attributes;
mod test_basic_block;
mod test_builder;
mod test_context;
-#[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
mod test_debug_info;
mod test_execution_engine;
mod test_instruction_conversion;
mod test_instruction_values;
+#[cfg(not(feature = "llvm8-0"))]
mod test_intrinsics;
mod test_module;
mod test_object_file;
-#[cfg(not(any(feature = "llvm17-0", feature = "llvm18-0")))]
+#[cfg(not(any(
+ feature = "llvm17-0",
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
+)))]
mod test_passes;
mod test_targets;
mod test_tari_example;
diff --git a/tests/all/test_attributes.rs b/tests/all/test_attributes.rs
index 92aab1cf073..00df668b0ac 100644
--- a/tests/all/test_attributes.rs
+++ b/tests/all/test_attributes.rs
@@ -227,7 +227,7 @@ fn test_attributes_on_call_site_values() {
assert!(call_site_value
.get_string_attribute(AttributeLoc::Return, "my_key")
.is_none());
- assert_eq!(call_site_value.get_called_fn_value(), fn_value);
+ assert_eq!(call_site_value.get_called_fn_value(), Some(fn_value));
call_site_value.set_alignment_attribute(AttributeLoc::Return, 16);
diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs
index d25f2a27581..932b0191fd8 100644
--- a/tests/all/test_builder.rs
+++ b/tests/all/test_builder.rs
@@ -47,19 +47,9 @@ fn test_build_call() {
let function3 = module.add_function("call_fn", fn_type2, None);
let basic_block3 = context.append_basic_block(function3, "entry");
let fn_ptr = function3.as_global_value().as_pointer_value();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let fn_ptr_type = fn_ptr.get_type();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let fn_ptr_type = context.ptr_type(AddressSpace::default());
builder.position_at_end(basic_block3);
@@ -68,36 +58,15 @@ fn test_build_call() {
builder.build_store(alloca, fn_ptr).unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let load = builder.build_load(alloca, "load").unwrap().into_pointer_value();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let load = builder
.build_load(fn_ptr_type, alloca, "load")
.unwrap()
.into_pointer_value();
#[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -115,7 +84,9 @@ fn test_build_call() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
builder.build_indirect_call(fn_type2, load, &[], "call").unwrap();
builder.build_return(None).unwrap();
@@ -179,19 +150,9 @@ fn test_build_invoke_cleanup_resume() {
};
// type of an exception in C++
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -263,19 +224,9 @@ fn test_build_invoke_catch_all() {
};
// type of an exception in C++
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -351,19 +302,9 @@ fn landing_pad_filter() {
};
// type of an exception in C++
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
@@ -409,19 +350,9 @@ fn test_null_checked_ptr_ops() {
// }
let i8_type = context.i8_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i64_type = context.i64_type();
let fn_type = i8_type.fn_type(&[i8_ptr_type.into()], false);
@@ -454,26 +385,9 @@ fn test_null_checked_ptr_ops() {
let new_ptr = builder
.build_int_to_ptr(new_ptr_as_int, i8_ptr_type, "int_as_ptr")
.unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let index1 = builder.build_load(new_ptr, "deref").unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let index1 = builder.build_load(i8_ptr_type, new_ptr, "deref").unwrap();
builder.build_return(Some(&index1)).unwrap();
@@ -513,26 +427,9 @@ fn test_null_checked_ptr_ops() {
let new_ptr = builder
.build_int_to_ptr(new_ptr_as_int, i8_ptr_type, "int_as_ptr")
.unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let index1 = builder.build_load(new_ptr, "deref").unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let index1 = builder.build_load(i8_ptr_type, new_ptr, "deref").unwrap();
builder.build_return(Some(&index1)).unwrap();
@@ -972,7 +869,6 @@ fn test_scalable_vector_convert_ops() {
assert!(fn_value.verify(true));
}
-#[llvm_versions(8..)]
#[test]
fn test_vector_convert_ops_respect_target_signedness() {
let context = Context::create();
@@ -1170,19 +1066,9 @@ fn test_vector_pointer_ops() {
let context = Context::create();
let module = context.create_module("test");
let int32_vec_type = context.i32_type().vec_type(4);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_vec_type = context.i8_type().ptr_type(AddressSpace::default()).vec_type(4);
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_vec_type = context.ptr_type(AddressSpace::default()).vec_type(4);
let bool_vec_type = context.bool_type().vec_type(4);
@@ -1207,19 +1093,9 @@ fn test_scalable_vector_pointer_ops() {
let context = Context::create();
let module = context.create_module("test");
let int32_vec_type = context.i32_type().scalable_vec_type(4);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_vec_type = context.i8_type().ptr_type(AddressSpace::default()).scalable_vec_type(4);
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_vec_type = context.ptr_type(AddressSpace::default()).scalable_vec_type(4);
let bool_vec_type = context.bool_type().scalable_vec_type(4);
@@ -1255,29 +1131,12 @@ fn test_insert_value() {
builder.position_at_end(entry);
let array_alloca = builder.build_alloca(array_type, "array_alloca").unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let array = builder
.build_load(array_alloca, "array_load")
.unwrap()
.into_array_value();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let array = builder
.build_load(array_type, array_alloca, "array_load")
.unwrap()
@@ -1314,29 +1173,12 @@ fn test_insert_value() {
.is_err_and(|e| e == BuilderError::ExtractOutOfRange));
let struct_alloca = builder.build_alloca(struct_type, "struct_alloca").unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let struct_value = builder
.build_load(struct_alloca, "struct_load")
.unwrap()
.into_struct_value();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let struct_value = builder
.build_load(struct_type, struct_alloca, "struct_load")
.unwrap()
@@ -1469,10 +1311,10 @@ fn is_alignment_ok(align: u32) -> bool {
// This replicates the assertions LLVM runs.
//
// See https://github.com/TheDan64/inkwell/issues/168
- align > 0 && align.is_power_of_two() && (align as f64).log2() < 64.0
+ // is_power_of_two returns false for 0.
+ align.is_power_of_two()
}
-#[llvm_versions(8..)]
#[test]
fn test_alignment_bytes() {
let verify_alignment = |alignment: u32| {
@@ -1483,11 +1325,10 @@ fn test_alignment_bytes() {
if is_alignment_ok(alignment) {
assert!(
result.is_ok() && module.verify().is_ok(),
- "alignment of {} was a power of 2 under 2^64, but did not verify for memcpy.",
- alignment
+ "alignment of {alignment} was a power of 2 under 2^64, but did not verify for memcpy."
);
} else {
- assert!(result.is_err(), "alignment of {} was a power of 2 under 2^64, yet verification passed for memcpy when it should not have.", alignment);
+ assert!(result.is_err(), "alignment of {alignment} was a power of 2 under 2^64, yet verification passed for memcpy when it should not have.");
}
let result = run_memmove_on(&context, &module, alignment);
@@ -1495,11 +1336,10 @@ fn test_alignment_bytes() {
if is_alignment_ok(alignment) {
assert!(
result.is_ok() && module.verify().is_ok(),
- "alignment of {} was a power of 2 under 2^64, but did not verify for memmove.",
- alignment
+ "alignment of {alignment} was a power of 2 under 2^64, but did not verify for memmove."
);
} else {
- assert!(result.is_err(), "alignment of {} was a power of 2 under 2^64, yet verification passed for memmove when it should not have.", alignment);
+ assert!(result.is_err(), "alignment of {alignment} was a power of 2 under 2^64, yet verification passed for memmove when it should not have.");
}
};
@@ -1510,7 +1350,6 @@ fn test_alignment_bytes() {
verify_alignment(u32::MAX);
}
-#[llvm_versions(8..)]
fn run_memcpy_on<'ctx>(
context: &'ctx Context,
module: &inkwell::module::Module<'ctx>,
@@ -1519,19 +1358,9 @@ fn run_memcpy_on<'ctx>(
let i32_type = context.i32_type();
let i64_type = context.i64_type();
let array_len = 4;
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let fn_type = i32_type.ptr_type(AddressSpace::default()).fn_type(&[], false);
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let fn_type = context.ptr_type(AddressSpace::default()).fn_type(&[], false);
let fn_value = module.add_function("test_fn", fn_type, None);
let builder = context.create_builder();
@@ -1540,32 +1369,16 @@ fn run_memcpy_on<'ctx>(
builder.position_at_end(entry);
let len_value = i64_type.const_int(array_len as u64, false);
+ #[cfg(not(feature = "typed-pointers"))]
let element_type = i32_type;
let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap();
// Initialize the array with the values [1, 2, 3, 4]
for index in 0..4 {
let index_val = i32_type.const_int(index, false);
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }.unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let elem_ptr = unsafe {
builder
.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index")
@@ -1581,26 +1394,9 @@ fn run_memcpy_on<'ctx>(
let bytes_to_copy = elems_to_copy * std::mem::size_of::();
let size_val = i64_type.const_int(bytes_to_copy as u64, false);
let index_val = i32_type.const_int(2, false);
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }.unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let dest_ptr = unsafe {
builder
.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index")
@@ -1614,7 +1410,6 @@ fn run_memcpy_on<'ctx>(
Ok(())
}
-#[llvm_versions(8..)]
#[test]
fn test_memcpy() {
// 1. Allocate an array with a few elements.
@@ -1627,7 +1422,7 @@ fn test_memcpy() {
// Verify the module
if let Err(errors) = module.verify() {
- panic!("Errors defining module: {:?}", errors);
+ panic!("Errors defining module: {errors:?}");
}
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
@@ -1642,7 +1437,6 @@ fn test_memcpy() {
}
}
-#[llvm_versions(8..)]
fn run_memmove_on<'ctx>(
context: &'ctx Context,
module: &inkwell::module::Module<'ctx>,
@@ -1651,19 +1445,9 @@ fn run_memmove_on<'ctx>(
let i32_type = context.i32_type();
let i64_type = context.i64_type();
let array_len = 4;
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let fn_type = i32_type.ptr_type(AddressSpace::default()).fn_type(&[], false);
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let fn_type = context.ptr_type(AddressSpace::default()).fn_type(&[], false);
let fn_value = module.add_function("test_fn", fn_type, None);
let builder = context.create_builder();
@@ -1672,32 +1456,16 @@ fn run_memmove_on<'ctx>(
builder.position_at_end(entry);
let len_value = i64_type.const_int(array_len as u64, false);
+ #[cfg(not(feature = "typed-pointers"))]
let element_type = i32_type;
let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap();
// Initialize the array with the values [1, 2, 3, 4]
for index in 0..4 {
let index_val = i32_type.const_int(index, false);
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }.unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let elem_ptr = unsafe {
builder
.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index")
@@ -1713,26 +1481,9 @@ fn run_memmove_on<'ctx>(
let bytes_to_copy = elems_to_copy * std::mem::size_of::();
let size_val = i64_type.const_int(bytes_to_copy as u64, false);
let index_val = i32_type.const_int(2, false);
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }.unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let dest_ptr = unsafe {
builder
.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index")
@@ -1746,7 +1497,6 @@ fn run_memmove_on<'ctx>(
Ok(())
}
-#[llvm_versions(8..)]
#[test]
fn test_memmove() {
// 1. Allocate an array with a few elements.
@@ -1759,7 +1509,7 @@ fn test_memmove() {
// Verify the module
if let Err(errors) = module.verify() {
- panic!("Errors defining module: {:?}", errors);
+ panic!("Errors defining module: {errors:?}");
}
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
@@ -1774,7 +1524,6 @@ fn test_memmove() {
}
}
-#[llvm_versions(8..)]
fn run_memset_on<'ctx>(
context: &'ctx Context,
module: &inkwell::module::Module<'ctx>,
@@ -1784,19 +1533,9 @@ fn run_memset_on<'ctx>(
let i32_type = context.i32_type();
let i64_type = context.i64_type();
let array_len = 4;
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let fn_type = i32_type.ptr_type(AddressSpace::default()).fn_type(&[], false);
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let fn_type = context.ptr_type(AddressSpace::default()).fn_type(&[], false);
let fn_value = module.add_function("test_fn", fn_type, None);
let builder = context.create_builder();
@@ -1805,6 +1544,7 @@ fn run_memset_on<'ctx>(
builder.position_at_end(entry);
let len_value = i64_type.const_int(array_len as u64, false);
+ #[cfg(not(feature = "typed-pointers"))]
let element_type = i32_type;
let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap();
@@ -1817,26 +1557,9 @@ fn run_memset_on<'ctx>(
// Memset the second half of the array as -1
let val = i8_type.const_all_ones();
let index = i32_type.const_int(2, false);
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let part_2 = unsafe { builder.build_in_bounds_gep(array_ptr, &[index], "index") }.unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let part_2 = unsafe {
builder
.build_in_bounds_gep(element_type, array_ptr, &[index], "index")
@@ -1848,7 +1571,6 @@ fn run_memset_on<'ctx>(
Ok(())
}
-#[llvm_versions(8..)]
#[test]
fn test_memset() {
// 1. Allocate an array with a few elements.
@@ -1861,7 +1583,7 @@ fn test_memset() {
// Verify the module
if let Err(errors) = module.verify() {
- panic!("Errors defining module: {:?}", errors);
+ panic!("Errors defining module: {errors:?}");
}
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
@@ -1887,33 +1609,13 @@ fn test_bit_cast() {
let i32_type = context.i32_type();
let f64_type = context.f64_type();
let i64_type = context.i64_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i64_ptr_type = i64_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i64_ptr_type = context.ptr_type(AddressSpace::default());
let i32_vec_type = i32_type.vec_type(2);
#[cfg(any(
@@ -1923,7 +1625,9 @@ fn test_bit_cast() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let i32_scalable_vec_type = i32_type.scalable_vec_type(2);
let arg_types = [
@@ -1939,7 +1643,9 @@ fn test_bit_cast() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
i32_scalable_vec_type.into(),
];
@@ -1959,7 +1665,9 @@ fn test_bit_cast() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let i32_scalable_vec_arg = fn_value.get_nth_param(5).unwrap();
@@ -1976,7 +1684,9 @@ fn test_bit_cast() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
{
let i64_scalable_vec_type = i64_type.scalable_vec_type(1);
@@ -2026,37 +1736,15 @@ fn test_atomicrmw() {
let i31_type = context.custom_width_int_type(31);
let i4_type = context.custom_width_int_type(4);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_value = i32_type.ptr_type(AddressSpace::default()).get_undef();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_value = context.ptr_type(AddressSpace::default()).get_undef();
let zero_value = i32_type.const_zero();
let result = builder.build_atomicrmw(AtomicRMWBinOp::Add, ptr_value, zero_value, AtomicOrdering::Unordered);
assert!(result.is_ok());
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
{
let i64_type = context.i64_type();
let ptr_value = i64_type.ptr_type(AddressSpace::default()).get_undef();
@@ -2065,37 +1753,17 @@ fn test_atomicrmw() {
assert!(result.is_err());
}
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_value = i31_type.ptr_type(AddressSpace::default()).get_undef();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_value = context.ptr_type(AddressSpace::default()).get_undef();
let zero_value = i31_type.const_zero();
let result = builder.build_atomicrmw(AtomicRMWBinOp::Add, ptr_value, zero_value, AtomicOrdering::Unordered);
assert!(result.is_err());
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_value = i4_type.ptr_type(AddressSpace::default()).get_undef();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_value = context.ptr_type(AddressSpace::default()).get_undef();
let zero_value = i4_type.const_zero();
let result = builder.build_atomicrmw(AtomicRMWBinOp::Add, ptr_value, zero_value, AtomicOrdering::Unordered);
@@ -2116,33 +1784,13 @@ fn test_cmpxchg() {
let i32_type = context.i32_type();
let i64_type = context.i64_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_ptr_type = i32_ptr_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_ptr_type = context.ptr_type(AddressSpace::default());
let ptr_value = i32_ptr_type.get_undef();
@@ -2217,19 +1865,7 @@ fn test_cmpxchg() {
);
assert!(result.is_err());
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
{
let ptr_value = i32_ptr_ptr_type.get_undef();
let zero_value = i32_type.const_zero();
@@ -2280,19 +1916,7 @@ fn test_cmpxchg() {
);
assert!(result.is_ok());
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
{
let ptr_value = i32_ptr_type.get_undef();
let zero_value = i32_ptr_type.const_zero();
@@ -2315,35 +1939,15 @@ fn test_safe_struct_gep() {
let module = context.create_module("struct_gep");
let void_type = context.void_type();
let i32_ty = context.i32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_ty = context.ptr_type(AddressSpace::default());
let field_types = &[i32_ty.into(), i32_ty.into()];
let struct_ty = context.struct_type(field_types, false);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let struct_ptr_ty = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_ty.into(), struct_ptr_ty.into()], false);
let fn_value = module.add_function("", fn_type, None);
@@ -2354,19 +1958,7 @@ fn test_safe_struct_gep() {
let i32_ptr = fn_value.get_first_param().unwrap().into_pointer_value();
let struct_ptr = fn_value.get_last_param().unwrap().into_pointer_value();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
{
assert!(builder.build_struct_gep(i32_ptr, 0, "struct_gep").is_err());
assert!(builder.build_struct_gep(i32_ptr, 10, "struct_gep").is_err());
@@ -2374,12 +1966,7 @@ fn test_safe_struct_gep() {
assert!(builder.build_struct_gep(struct_ptr, 1, "struct_gep").is_ok());
assert!(builder.build_struct_gep(struct_ptr, 2, "struct_gep").is_err());
}
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
{
assert!(builder.build_struct_gep(i32_ty, i32_ptr, 0, "struct_gep").is_err());
assert!(builder.build_struct_gep(i32_ty, i32_ptr, 10, "struct_gep").is_err());
diff --git a/tests/all/test_context.rs b/tests/all/test_context.rs
index 003eedf1439..98038642646 100644
--- a/tests/all/test_context.rs
+++ b/tests/all/test_context.rs
@@ -53,19 +53,9 @@ fn test_values_get_context() {
let i8_type = context.i8_type();
let f32_type = context.f32_type();
let f32_vec_type = f32_type.vec_type(3);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let f32_ptr_type = context.ptr_type(AddressSpace::default());
let f32_array_type = f32_type.array_type(2);
let fn_type = f32_type.fn_type(&[], false);
diff --git a/tests/all/test_debug_info.rs b/tests/all/test_debug_info.rs
index 31408f0ef92..b7ca7cffd8f 100644
--- a/tests/all/test_debug_info.rs
+++ b/tests/all/test_debug_info.rs
@@ -33,7 +33,9 @@ fn test_smoke() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -44,19 +46,15 @@ fn test_smoke() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
let ditype = dibuilder
- .create_basic_type(
- "type_name",
- 0_u64,
- 0x00,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::PUBLIC,
- )
+ .create_basic_type("type_name", 0_u64, 0x00, DIFlags::PUBLIC)
.unwrap();
let subroutine_type =
dibuilder.create_subroutine_type(compile_unit.get_file(), Some(ditype.as_type()), &[], DIFlags::PUBLIC);
@@ -86,9 +84,9 @@ fn test_smoke() {
let loc = dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
- #[cfg(any(feature = "llvm7-0", feature = "llvm8-0",))]
+ #[cfg(feature = "llvm8-0")]
builder.set_current_debug_location(&context, loc);
- #[cfg(not(any(feature = "llvm7-0", feature = "llvm8-0",)))]
+ #[cfg(not(feature = "llvm8-0"))]
builder.set_current_debug_location(loc);
dibuilder.finalize();
@@ -123,7 +121,9 @@ fn test_struct_with_placeholders() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -134,48 +134,18 @@ fn test_struct_with_placeholders() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
// Some byte aligned integer types.
- let i32ty = dibuilder
- .create_basic_type(
- "i32",
- 32,
- 0x07,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::PUBLIC,
- )
- .unwrap();
- let i64ty = dibuilder
- .create_basic_type(
- "i64",
- 64,
- 0x07,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::PUBLIC,
- )
- .unwrap();
- let f32ty = dibuilder
- .create_basic_type(
- "f32",
- 32,
- 0x04,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::PUBLIC,
- )
- .unwrap();
- let f64ty = dibuilder
- .create_basic_type(
- "f64",
- 64,
- 0x04,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::PUBLIC,
- )
- .unwrap();
+ let i32ty = dibuilder.create_basic_type("i32", 32, 0x07, DIFlags::PUBLIC).unwrap();
+ let i64ty = dibuilder.create_basic_type("i64", 64, 0x07, DIFlags::PUBLIC).unwrap();
+ let f32ty = dibuilder.create_basic_type("f32", 32, 0x04, DIFlags::PUBLIC).unwrap();
+ let f64ty = dibuilder.create_basic_type("f64", 64, 0x04, DIFlags::PUBLIC).unwrap();
let member_sizes = [32, 64, 32, 64];
let member_types = [i32ty, i64ty, f32ty, f64ty];
@@ -255,7 +225,9 @@ fn test_no_explicit_finalize() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -266,7 +238,9 @@ fn test_no_explicit_finalize() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
@@ -276,7 +250,6 @@ fn test_no_explicit_finalize() {
assert!(module.verify().is_ok());
}
-#[llvm_versions(8..)]
#[test]
fn test_replacing_placeholder_with_placeholder() {
let context = Context::create();
@@ -304,7 +277,9 @@ fn test_replacing_placeholder_with_placeholder() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -315,7 +290,9 @@ fn test_replacing_placeholder_with_placeholder() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
@@ -367,7 +344,9 @@ fn test_anonymous_basic_type() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -378,24 +357,19 @@ fn test_anonymous_basic_type() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
assert_eq!(
- dibuilder.create_basic_type(
- "",
- 0_u64,
- 0x00,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::ZERO
- ),
- Err("basic types must have names")
+ dibuilder.create_basic_type("", 0_u64, 0x00, DIFlags::ZERO),
+ Err(inkwell::Error::EmptyNameError)
);
}
-#[llvm_versions(8..)]
#[test]
fn test_global_expressions() {
let context = Context::create();
@@ -423,7 +397,9 @@ fn test_global_expressions() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -434,7 +410,9 @@ fn test_global_expressions() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
@@ -497,7 +475,9 @@ fn test_pointer_types() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -508,19 +488,15 @@ fn test_pointer_types() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
let di_type = dibuilder
- .create_basic_type(
- "type_name",
- 8_u64,
- 0x00,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::ZERO,
- )
+ .create_basic_type("type_name", 8_u64, 0x00, DIFlags::ZERO)
.unwrap()
.as_type();
@@ -555,7 +531,9 @@ fn test_reference_types() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -566,19 +544,15 @@ fn test_reference_types() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
let di_type = dibuilder
- .create_basic_type(
- "type_name",
- 8_u64,
- 0x00,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::ZERO,
- )
+ .create_basic_type("type_name", 8_u64, 0x00, DIFlags::ZERO)
.unwrap()
.as_type();
@@ -614,7 +588,9 @@ fn test_array_type() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
#[cfg(any(
@@ -625,19 +601,15 @@ fn test_array_type() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
"",
);
let di_type = dibuilder
- .create_basic_type(
- "type_name",
- 8_u64,
- 0x00,
- #[cfg(not(feature = "llvm7-0"))]
- DIFlags::ZERO,
- )
+ .create_basic_type("type_name", 8_u64, 0x00, DIFlags::ZERO)
.unwrap()
.as_type();
diff --git a/tests/all/test_execution_engine.rs b/tests/all/test_execution_engine.rs
index bd056f00003..84b7dd7e190 100644
--- a/tests/all/test_execution_engine.rs
+++ b/tests/all/test_execution_engine.rs
@@ -1,8 +1,22 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
use inkwell::context::Context;
use inkwell::execution_engine::FunctionLookupError;
-use inkwell::targets::{InitializationConfig, Target};
+use inkwell::memory_manager::McjitMemoryManager;
+use inkwell::module::Linkage;
+use inkwell::targets::{CodeModel, InitializationConfig, Target};
use inkwell::{AddressSpace, IntPredicate, OptimizationLevel};
+#[cfg(target_os = "windows")]
+use windows::Win32::System::{
+ Memory::{
+ VirtualAlloc, VirtualFree, VirtualProtect, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_EXECUTE_READ,
+ PAGE_READWRITE,
+ },
+ SystemInformation::{GetSystemInfo, SYSTEM_INFO},
+};
+
type Thunk = unsafe extern "C" fn();
#[test]
@@ -54,22 +68,12 @@ fn test_jit_execution_engine() {
let module = context.create_module("main_module");
let builder = context.create_builder();
let i32_type = context.i32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_ptr_type = context
.i8_type()
.ptr_type(AddressSpace::default())
.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_ptr_type = context.ptr_type(AddressSpace::default());
let one_i32 = i32_type.const_int(1, false);
let three_i32 = i32_type.const_int(3, false);
@@ -118,11 +122,11 @@ fn test_jit_execution_engine() {
let ret = unsafe { execution_engine.run_function_as_main(main, &["input", "bar"]) };
- assert_eq!(ret, 1, "unexpected main return code: {}", ret);
+ assert_eq!(ret, 1, "unexpected main return code: {ret}");
let ret = unsafe { execution_engine.run_function_as_main(main, &["input", "bar", "baz"]) };
- assert_eq!(ret, 42, "unexpected main return code: {}", ret);
+ assert_eq!(ret, 42, "unexpected main return code: {ret}");
}
// #[test]
@@ -150,6 +154,122 @@ fn test_interpreter_execution_engine() {
assert!(module.create_interpreter_execution_engine().is_ok());
}
+#[test]
+
+fn test_mcjit_execution_engine_with_memory_manager() {
+ let mmgr = MockMemoryManager::new();
+ let mmgr_for_test = mmgr.clone();
+
+ {
+ let context = Context::create();
+ let module = context.create_module("main_module");
+ let builder = context.create_builder();
+
+ // Define @llvm.experimental.stackmap
+ let fn_type = context
+ .void_type()
+ .fn_type(&[context.i64_type().into(), context.i32_type().into()], true);
+ let stackmap_func = module.add_function("llvm.experimental.stackmap", fn_type, Some(Linkage::External));
+
+ // Set up the function
+ //
+ // `@llvm.experimental.stackmap` a call is present, LLVM will emit a separate stackmap section,
+ // causing the `allocate_data_section` callback to be invoked an additional
+ // time to handle the stackmap data. Specifically:
+ // ```
+ // f64 test_fn() {
+ // entry:
+ // call void @llvm.experimental.stackmap(i64 12345, i32 0)
+ // ret f64 64.0
+ // }
+ // ```
+ let double = context.f64_type();
+ let sig = double.fn_type(&[], false);
+ let f = module.add_function("test_fn", sig, None);
+ let b = context.append_basic_block(f, "entry");
+ builder.position_at_end(b);
+
+ // Create a call to the stackmap intrinsic
+ // Stack maps are used by the garbage collector to find roots on the stack
+ // See: https://llvm.org/docs/StackMaps.html#intrinsics
+ builder
+ .build_call(
+ stackmap_func,
+ &[
+ context.i64_type().const_int(12345, false).into(),
+ context.i32_type().const_int(0, false).into(),
+ ],
+ "call_stackmap",
+ )
+ .unwrap();
+
+ // Insert a return statement
+ let ret = double.const_float(64.0);
+ builder.build_return(Some(&ret)).unwrap();
+
+ module.verify().unwrap();
+
+ let ee = module
+ .create_mcjit_execution_engine_with_memory_manager(
+ mmgr,
+ OptimizationLevel::None,
+ CodeModel::Default,
+ false,
+ false,
+ )
+ .unwrap();
+
+ unsafe {
+ let test_fn = ee.get_function:: f64>("test_fn").unwrap();
+ let return_value = test_fn.call();
+ assert_eq!(return_value, 64.0);
+ }
+ }
+ // ee dropped here. Destroy should be called
+
+ let data = mmgr_for_test.data.borrow();
+ assert_eq!(1, data.code_alloc_calls);
+ assert!(
+ data.data_alloc_calls >= 2,
+ "Expected at least 2 calls to allocate_data_section, but got {}. \
+ We've observed that LLVM 5 typically calls it 3 times, while LLVM 18 often calls it only 2.",
+ data.data_alloc_calls
+ );
+ assert_eq!(1, data.finalize_calls);
+ assert_eq!(1, data.destroy_calls);
+}
+
+#[test]
+fn test_create_mcjit_engine_when_already_owned() {
+ let context = Context::create();
+ let module = context.create_module("owned_module");
+
+ // First engine should succeed
+ let memory_manager = MockMemoryManager::new();
+ let engine_result = module.create_mcjit_execution_engine_with_memory_manager(
+ memory_manager,
+ OptimizationLevel::None,
+ CodeModel::Default,
+ false,
+ false,
+ );
+ assert!(engine_result.is_ok());
+
+ // Second engine should fail
+ let memory_manager2 = MockMemoryManager::new();
+ let second_result = module.create_mcjit_execution_engine_with_memory_manager(
+ memory_manager2,
+ OptimizationLevel::None,
+ CodeModel::Default,
+ false,
+ false,
+ );
+ assert!(
+ second_result.is_err(),
+ "Expected an error when creating a second ExecutionEngine on the same module"
+ );
+}
+
#[test]
fn test_add_remove_module() {
let context = Context::create();
@@ -235,3 +355,204 @@ fn test_add_remove_module() {
// module.create_jit_execution_engine(OptimizationLevel::None).unwrap()
// };
// }
+
+/// A mock memory manager that allocates memory in fixed-size pages for testing.
+#[derive(Debug, Clone)]
+struct MockMemoryManager {
+ data: Rc>,
+}
+
+#[derive(Debug)]
+struct MockMemoryManagerData {
+ fixed_capacity_bytes: usize,
+ fixed_page_size: usize,
+
+ code_buff_ptr: std::ptr::NonNull,
+ code_offset: usize,
+
+ data_buff_ptr: std::ptr::NonNull,
+ data_offset: usize,
+
+ /// Count call to callbacks for testing
+ code_alloc_calls: usize,
+ data_alloc_calls: usize,
+ finalize_calls: usize,
+ destroy_calls: usize,
+}
+
+impl MockMemoryManager {
+ pub fn new() -> Self {
+ let capacity_bytes = 128 * 1024;
+ #[cfg(unix)]
+ let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
+
+ #[cfg(target_os = "windows")]
+ let page_size = {
+ let mut info = std::mem::MaybeUninit::::uninit();
+ unsafe {
+ GetSystemInfo(info.as_mut_ptr());
+ }
+ let info = unsafe { info.assume_init() };
+ info.dwPageSize as usize
+ };
+
+ #[cfg(unix)]
+ let code_buff_ptr = unsafe {
+ std::ptr::NonNull::new_unchecked(libc::mmap(
+ std::ptr::null_mut(),
+ capacity_bytes,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+ -1,
+ 0,
+ ) as *mut u8)
+ };
+
+ #[cfg(target_os = "windows")]
+ let code_buff_ptr = unsafe {
+ std::ptr::NonNull::new_unchecked(
+ VirtualAlloc(None, capacity_bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE).cast::(),
+ )
+ };
+
+ #[cfg(unix)]
+ let data_buff_ptr = unsafe {
+ std::ptr::NonNull::new_unchecked(libc::mmap(
+ std::ptr::null_mut(),
+ capacity_bytes,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+ -1,
+ 0,
+ ) as *mut u8)
+ };
+
+ #[cfg(target_os = "windows")]
+ let data_buff_ptr = unsafe {
+ std::ptr::NonNull::new_unchecked(
+ VirtualAlloc(None, capacity_bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE).cast::(),
+ )
+ };
+
+ Self {
+ data: Rc::new(RefCell::new(MockMemoryManagerData {
+ fixed_capacity_bytes: capacity_bytes,
+ fixed_page_size: page_size,
+
+ code_buff_ptr,
+ code_offset: 0,
+
+ data_buff_ptr,
+ data_offset: 0,
+
+ code_alloc_calls: 0,
+ data_alloc_calls: 0,
+ finalize_calls: 0,
+ destroy_calls: 0,
+ })),
+ }
+ }
+}
+
+impl McjitMemoryManager for MockMemoryManager {
+ fn allocate_code_section(
+ &mut self,
+ size: libc::size_t,
+ _alignment: libc::c_uint,
+ _section_id: libc::c_uint,
+ _section_name: &str,
+ ) -> *mut u8 {
+ let mut data = self.data.borrow_mut();
+ data.code_alloc_calls += 1;
+
+ let alloc_size = size.div_ceil(data.fixed_page_size) * data.fixed_page_size;
+ let ptr = unsafe { data.code_buff_ptr.as_ptr().add(data.code_offset) };
+ data.code_offset += alloc_size;
+
+ ptr
+ }
+
+ fn allocate_data_section(
+ &mut self,
+ size: libc::size_t,
+ _alignment: libc::c_uint,
+ _section_id: libc::c_uint,
+ _section_name: &str,
+ _is_read_only: bool,
+ ) -> *mut u8 {
+ let mut data = self.data.borrow_mut();
+
+ data.data_alloc_calls += 1;
+
+ let alloc_size = size.div_ceil(data.fixed_page_size) * data.fixed_page_size;
+ let ptr = unsafe { data.data_buff_ptr.as_ptr().add(data.data_offset) };
+ data.data_offset += alloc_size;
+
+ ptr
+ }
+
+ fn finalize_memory(&mut self) -> Result<(), String> {
+ let mut data = self.data.borrow_mut();
+
+ data.finalize_calls += 1;
+
+ #[cfg(unix)]
+ unsafe {
+ libc::mprotect(
+ data.code_buff_ptr.as_ptr() as *mut libc::c_void,
+ data.fixed_capacity_bytes,
+ libc::PROT_READ | libc::PROT_EXEC,
+ );
+ libc::mprotect(
+ data.data_buff_ptr.as_ptr() as *mut libc::c_void,
+ data.fixed_capacity_bytes,
+ libc::PROT_READ | libc::PROT_WRITE,
+ );
+ }
+
+ #[cfg(windows)]
+ unsafe {
+ let mut old_protect = PAGE_READWRITE;
+ VirtualProtect(
+ data.code_buff_ptr.as_ptr() as *mut _,
+ data.fixed_capacity_bytes,
+ PAGE_EXECUTE_READ,
+ &mut old_protect,
+ )
+ .expect("VirtualProtect failed");
+ VirtualProtect(
+ data.data_buff_ptr.as_ptr() as *mut _,
+ data.fixed_capacity_bytes,
+ PAGE_READWRITE,
+ &mut old_protect,
+ )
+ .expect("VirtualProtect failed");
+ }
+
+ Ok(())
+ }
+
+ fn destroy(&mut self) {
+ let mut data = self.data.borrow_mut();
+
+ data.destroy_calls += 1;
+
+ #[cfg(unix)]
+ unsafe {
+ libc::munmap(
+ data.code_buff_ptr.as_ptr() as *mut libc::c_void,
+ data.fixed_capacity_bytes,
+ );
+ libc::munmap(
+ data.data_buff_ptr.as_ptr() as *mut libc::c_void,
+ data.fixed_capacity_bytes,
+ );
+ }
+
+ #[cfg(windows)]
+ unsafe {
+ VirtualFree(data.code_buff_ptr.as_ptr() as *mut _, 0, MEM_RELEASE).expect("Failed to free memory.");
+ VirtualFree(data.data_buff_ptr.as_ptr() as *mut _, 0, MEM_RELEASE).expect("Failed to free memory.");
+ }
+ }
+}
diff --git a/tests/all/test_instruction_conversion.rs b/tests/all/test_instruction_conversion.rs
index e129e711af9..eadabf93670 100644
--- a/tests/all/test_instruction_conversion.rs
+++ b/tests/all/test_instruction_conversion.rs
@@ -103,26 +103,16 @@ fn test_conversion_to_pointer_value() {
let module = context.create_module("testing");
let builder = context.create_builder();
- // Create a function whose the first parameter is of IntType
+ // Create a function with no parameters
let fn_type = context.void_type().fn_type(&[], false);
let function = module.add_function("testing", fn_type, None);
let basic_block = context.append_basic_block(function, "entry");
builder.position_at_end(basic_block);
// Create a PointerType instruction
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i64_ptr_type = context.i64_type().ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i64_ptr_type = context.ptr_type(AddressSpace::default());
let alloca_instr = builder
.build_alloca(i64_ptr_type, "alloca")
@@ -130,7 +120,7 @@ fn test_conversion_to_pointer_value() {
.as_instruction()
.unwrap();
- // Test the instruction conversion to a FloatValue
+ // Test the instruction conversion to a PointerValue
let ptr_conversion: Result = alloca_instr.try_into();
assert!(ptr_conversion.is_ok());
diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs
index 04d9a1c6440..3b120742e96 100644
--- a/tests/all/test_instruction_values.rs
+++ b/tests/all/test_instruction_values.rs
@@ -1,7 +1,11 @@
use inkwell::context::Context;
-use inkwell::types::{AnyType, AnyTypeEnum, BasicType};
+#[cfg(not(feature = "typed-pointers"))]
+use inkwell::types::AnyType;
+use inkwell::types::{AnyTypeEnum, BasicType};
use inkwell::values::{BasicValue, CallSiteValue, InstructionOpcode::*};
-use inkwell::{AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate};
+#[llvm_versions(10..)]
+use inkwell::AtomicRMWBinOp;
+use inkwell::{AddressSpace, AtomicOrdering, FloatPredicate, IntPredicate};
#[test]
#[ignore]
@@ -11,19 +15,9 @@ fn test_operands() {
let builder = context.create_builder();
let void_type = context.void_type();
let f32_type = context.f32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let f32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
@@ -87,19 +81,7 @@ fn test_operands() {
assert!(free_instruction.set_operand(0, arg1));
// Module is no longer valid because free takes an i8* not f32*
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
assert!(module.verify().is_err());
assert!(free_instruction.set_operand(0, free_operand0));
@@ -267,19 +249,9 @@ fn test_instructions() {
let void_type = context.void_type();
let i64_type = context.i64_type();
let f32_type = context.f32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let f32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);
@@ -311,14 +283,9 @@ fn test_instructions() {
.build_conditional_branch(i64_type.const_zero(), basic_block, basic_block)
.unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
{
- let gep_instr = unsafe { builder.build_gep(i64_type, alloca_val, &vec![], "gep").unwrap() };
+ let gep_instr = unsafe { builder.build_gep(i64_type, alloca_val, &[], "gep").unwrap() };
assert_eq!(
gep_instr
.as_instruction_value()
@@ -391,19 +358,9 @@ fn test_volatile_atomicrmw_cmpxchg() {
let void_type = context.void_type();
let i32_type = context.i32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_type.into(), i32_type.into()], false);
@@ -437,6 +394,10 @@ fn test_volatile_atomicrmw_cmpxchg() {
.as_instruction_value()
.unwrap();
+ // Test get_atomic_rmw_bin_op
+ assert_eq!(atomicrmw.get_atomic_rmw_bin_op(), Some(AtomicRMWBinOp::Add));
+ assert_eq!(cmpxchg.get_atomic_rmw_bin_op(), None);
+
assert!(!atomicrmw.get_volatile().unwrap());
assert!(!cmpxchg.get_volatile().unwrap());
atomicrmw.set_volatile(true).unwrap();
@@ -458,19 +419,9 @@ fn test_mem_instructions() {
let void_type = context.void_type();
let f32_type = context.f32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let f32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);
@@ -491,16 +442,16 @@ fn test_mem_instructions() {
let load = builder.build_load(arg1, "").unwrap();
let load_instruction = load.as_instruction_value().unwrap();
- assert_eq!(store_instruction.get_volatile().unwrap(), false);
- assert_eq!(load_instruction.get_volatile().unwrap(), false);
+ assert!(!store_instruction.get_volatile().unwrap());
+ assert!(!load_instruction.get_volatile().unwrap());
store_instruction.set_volatile(true).unwrap();
load_instruction.set_volatile(true).unwrap();
- assert_eq!(store_instruction.get_volatile().unwrap(), true);
- assert_eq!(load_instruction.get_volatile().unwrap(), true);
+ assert!(store_instruction.get_volatile().unwrap());
+ assert!(load_instruction.get_volatile().unwrap());
store_instruction.set_volatile(false).unwrap();
load_instruction.set_volatile(false).unwrap();
- assert_eq!(store_instruction.get_volatile().unwrap(), false);
- assert_eq!(load_instruction.get_volatile().unwrap(), false);
+ assert!(!store_instruction.get_volatile().unwrap());
+ assert!(!load_instruction.get_volatile().unwrap());
assert_eq!(store_instruction.get_alignment().unwrap(), 0);
assert_eq!(load_instruction.get_alignment().unwrap(), 0);
@@ -508,13 +459,13 @@ fn test_mem_instructions() {
assert!(load_instruction.set_alignment(16).is_ok());
assert_eq!(store_instruction.get_alignment().unwrap(), 16);
assert_eq!(load_instruction.get_alignment().unwrap(), 16);
- assert!(store_instruction.set_alignment(0).is_ok());
- assert!(load_instruction.set_alignment(0).is_ok());
- assert_eq!(store_instruction.get_alignment().unwrap(), 0);
- assert_eq!(load_instruction.get_alignment().unwrap(), 0);
+ assert!(store_instruction.set_alignment(0).is_err());
+ assert!(load_instruction.set_alignment(0).is_err());
+ assert_eq!(store_instruction.get_alignment().unwrap(), 16);
+ assert_eq!(load_instruction.get_alignment().unwrap(), 16);
assert!(store_instruction.set_alignment(14).is_err());
- assert_eq!(store_instruction.get_alignment().unwrap(), 0);
+ assert_eq!(store_instruction.get_alignment().unwrap(), 16);
let fadd_instruction = builder
.build_float_add(load.into_float_value(), f32_val, "")
@@ -536,19 +487,9 @@ fn test_mem_instructions() {
let void_type = context.void_type();
let f32_type = context.f32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let f32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);
@@ -566,26 +507,9 @@ fn test_mem_instructions() {
let f32_val = f32_type.const_float(std::f64::consts::PI);
let store_instruction = builder.build_store(arg1, f32_val).unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let load = builder.build_load(arg1, "").unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let load = builder.build_load(f32_type, arg1, "").unwrap();
let load_instruction = load.as_instruction_value().unwrap();
@@ -633,19 +557,9 @@ fn test_atomic_ordering_mem_instructions() {
let void_type = context.void_type();
let f32_type = context.f32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let f32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);
@@ -663,26 +577,9 @@ fn test_atomic_ordering_mem_instructions() {
let f32_val = f32_type.const_float(std::f64::consts::PI);
let store_instruction = builder.build_store(arg1, f32_val).unwrap();
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
let load = builder.build_load(arg1, "").unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let load = builder.build_load(f32_type, arg1, "").unwrap();
let load_instruction = load.as_instruction_value().unwrap();
@@ -726,19 +623,9 @@ fn test_metadata_kinds() {
let i8_type = context.i8_type();
let f32_type = context.f32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_type = i8_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
let struct_type = context.struct_type(&[i8_type.into(), f32_type.into()], false);
let vector_type = i8_type.vec_type(2);
@@ -773,19 +660,9 @@ fn test_find_instruction_with_name() {
let void_type = context.void_type();
let i32_type = context.i32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
@@ -931,3 +808,105 @@ fn test_or_disjoint_flag() {
assert_eq!(i32_and.get_disjoint_flag(), None);
}
+
+#[test]
+fn test_instruction_indices() {
+ let context = Context::create();
+ let module = context.create_module("testing");
+ let builder = context.create_builder();
+
+ let void_type = context.void_type();
+ let i32_type = context.i32_type();
+ let f32_type = context.f32_type();
+ let struct_type = context.struct_type(&[i32_type.into(), f32_type.into(), i32_type.into()], false);
+ let array_type = i32_type.array_type(3);
+ let fn_type = void_type.fn_type(&[], false);
+
+ let function = module.add_function("test_indices", fn_type, None);
+ let basic_block = context.append_basic_block(function, "entry");
+
+ builder.position_at_end(basic_block);
+
+ // Create actual instruction values by using alloca and load
+ let struct_alloca = builder.build_alloca(struct_type, "struct_alloca").unwrap();
+ #[cfg(feature = "typed-pointers")]
+ let struct_val = builder.build_load(struct_alloca, "struct_load").unwrap();
+ #[cfg(not(feature = "typed-pointers"))]
+ let struct_val = builder.build_load(struct_type, struct_alloca, "struct_load").unwrap();
+
+ // Test with struct ExtractValue - now these will be instructions
+ let extract_struct_0 = builder
+ .build_extract_value(struct_val.into_struct_value(), 0, "extract_0")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+ let extract_struct_1 = builder
+ .build_extract_value(struct_val.into_struct_value(), 1, "extract_1")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+ let extract_struct_2 = builder
+ .build_extract_value(struct_val.into_struct_value(), 2, "extract_2")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+
+ assert_eq!(extract_struct_0.get_num_indices(), 1);
+ assert_eq!(extract_struct_0.get_indices(), vec![0]);
+ assert_eq!(extract_struct_1.get_num_indices(), 1);
+ assert_eq!(extract_struct_1.get_indices(), vec![1]);
+ assert_eq!(extract_struct_2.get_num_indices(), 1);
+ assert_eq!(extract_struct_2.get_indices(), vec![2]);
+
+ // Test with array ExtractValue
+ let array_alloca = builder.build_alloca(array_type, "array_alloca").unwrap();
+ #[cfg(feature = "typed-pointers")]
+ let array_val = builder.build_load(array_alloca, "array_load").unwrap();
+ #[cfg(not(feature = "typed-pointers"))]
+ let array_val = builder.build_load(array_type, array_alloca, "array_load").unwrap();
+
+ let extract_array_0 = builder
+ .build_extract_value(array_val.into_array_value(), 0, "extract_arr_0")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+ let extract_array_1 = builder
+ .build_extract_value(array_val.into_array_value(), 1, "extract_arr_1")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+
+ assert_eq!(extract_array_0.get_num_indices(), 1);
+ assert_eq!(extract_array_0.get_indices(), vec![0]);
+ assert_eq!(extract_array_1.get_num_indices(), 1);
+ assert_eq!(extract_array_1.get_indices(), vec![1]);
+
+ // Test with InsertValue
+ let i32_val = i32_type.const_int(42, false);
+ let insert_struct_0 = builder
+ .build_insert_value(struct_val.into_struct_value(), i32_val, 0, "insert_0")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+ let insert_struct_2 = builder
+ .build_insert_value(struct_val.into_struct_value(), i32_val, 2, "insert_2")
+ .unwrap()
+ .as_instruction_value()
+ .unwrap();
+
+ assert_eq!(insert_struct_0.get_num_indices(), 1);
+ assert_eq!(insert_struct_0.get_indices(), vec![0]);
+ assert_eq!(insert_struct_2.get_num_indices(), 1);
+ assert_eq!(insert_struct_2.get_indices(), vec![2]);
+
+ // Test with non-extractvalue/insertvalue instruction (should return 0/empty)
+ let i32_alloca = builder.build_alloca(i32_type, "i32_alloca").unwrap();
+ let store_inst = builder.build_store(i32_alloca, i32_val).unwrap();
+
+ assert_eq!(store_inst.get_num_indices(), 0);
+ assert_eq!(store_inst.get_indices(), vec![]);
+
+ builder.build_return(None).unwrap();
+
+ assert!(module.verify().is_ok());
+}
diff --git a/tests/all/test_intrinsics.rs b/tests/all/test_intrinsics.rs
index 9adb66caa00..099b8f5c294 100644
--- a/tests/all/test_intrinsics.rs
+++ b/tests/all/test_intrinsics.rs
@@ -1,19 +1,16 @@
use inkwell::context::Context;
use inkwell::intrinsics::Intrinsic;
-#[llvm_versions(9..)]
#[test]
fn test_get_cos() {
Intrinsic::find("llvm.cos").unwrap();
}
-#[llvm_versions(9..)]
#[test]
fn test_get_nonexistent() {
assert!(Intrinsic::find("nonsense").is_none())
}
-#[llvm_versions(9..)]
#[test]
fn test_get_decl_cos() {
let cos = Intrinsic::find("llvm.cos").unwrap();
@@ -31,12 +28,16 @@ fn test_get_decl_cos() {
assert_eq!(decl.get_name().to_str().unwrap(), "llvm.cos.f32");
}
-#[llvm_versions(9..)]
+#[llvm_versions(..19)]
#[test]
fn test_get_decl_va_copy() {
let va_copy = Intrinsic::find("llvm.va_copy").unwrap();
- assert!(!va_copy.is_overloaded());
+ // Looks like starting from LLVM 19, this is overloaded?
+ #[cfg(not(any(feature = "llvm19-1", feature = "llvm20-1")))]
+ {
+ assert!(!va_copy.is_overloaded());
+ }
let context = Context::create();
let module = context.create_module("my_module");
diff --git a/tests/all/test_module.rs b/tests/all/test_module.rs
index aa88002d47c..5ee645912e7 100644
--- a/tests/all/test_module.rs
+++ b/tests/all/test_module.rs
@@ -305,7 +305,7 @@ fn test_clone() {
}
#[test]
-fn test_print_to_file() {
+fn test_print_to_file_good_path() {
let context = Context::create();
let module = context.create_module("mod");
let void_type = context.void_type();
@@ -317,13 +317,6 @@ fn test_print_to_file() {
builder.position_at_end(basic_block);
builder.build_return(None).unwrap();
- let bad_path = Path::new("/tmp/some/silly/path/that/sure/doesn't/exist");
-
- assert_eq!(
- module.print_to_file(bad_path).unwrap_err().to_str(),
- Ok("No such file or directory")
- );
-
let mut temp_path = temp_dir();
temp_path.push("module");
@@ -331,6 +324,31 @@ fn test_print_to_file() {
assert!(module.print_to_file(&temp_path).is_ok());
}
+#[test]
+fn test_print_to_file_bad_path() {
+ let context = Context::create();
+ let module = context.create_module("mod");
+ let void_type = context.void_type();
+ let fn_type = void_type.fn_type(&[], false);
+ let f = module.add_function("f", fn_type, None);
+ let basic_block = context.append_basic_block(f, "entry");
+ let builder = context.create_builder();
+
+ builder.position_at_end(basic_block);
+ builder.build_return(None).unwrap();
+
+ #[cfg(unix)]
+ let bad_path = Path::new("/tmp/some/silly/path/that/sure/doesn't/exist");
+ #[cfg(windows)]
+ let bad_path = Path::new("/does/not/exist/hopefully");
+
+ match module.print_to_file(bad_path).unwrap_err().to_str() {
+ Ok("no such file or directory") | Ok("No such file or directory") => (),
+ Ok(err) => panic!("Some other error: {err}"),
+ Err(_) => panic!("Should have failed."),
+ }
+}
+
#[test]
fn test_get_set_target() {
Target::initialize_x86(&Default::default());
@@ -341,7 +359,6 @@ fn test_get_set_target() {
assert_eq!(module.get_name().to_str(), Ok("mod"));
assert_eq!(module.get_triple(), TargetTriple::create(""));
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
assert_eq!(module.get_source_file_name().to_str(), Ok("mod"));
module.set_name("mod2");
@@ -350,13 +367,10 @@ fn test_get_set_target() {
assert_eq!(module.get_name().to_str(), Ok("mod2"));
assert_eq!(module.get_triple(), triple);
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- module.set_source_file_name("foo.rs");
+ module.set_source_file_name("foo.rs");
- assert_eq!(module.get_source_file_name().to_str(), Ok("foo.rs"));
- assert_eq!(module.get_name().to_str(), Ok("mod2"));
- }
+ assert_eq!(module.get_source_file_name().to_str(), Ok("foo.rs"));
+ assert_eq!(module.get_name().to_str(), Ok("mod2"));
}
#[test]
@@ -433,40 +447,37 @@ fn test_linking_modules() {
#[test]
fn test_metadata_flags() {
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- let context = Context::create();
- let module = context.create_module("my_module");
+ let context = Context::create();
+ let module = context.create_module("my_module");
- use inkwell::module::FlagBehavior;
+ use inkwell::module::FlagBehavior;
- assert!(module.get_flag("some_key").is_none());
+ assert!(module.get_flag("some_key").is_none());
- let md = context.metadata_string("lots of metadata here");
+ let md = context.metadata_string("lots of metadata here");
- module.add_metadata_flag("some_key", FlagBehavior::Error, md);
+ module.add_metadata_flag("some_key", FlagBehavior::Error, md);
- // These have different addresses but same value
- assert!(module.get_flag("some_key").is_some());
+ // These have different addresses but same value
+ assert!(module.get_flag("some_key").is_some());
- let f64_type = context.f64_type();
- let f64_val = f64_type.const_float(std::f64::consts::PI);
+ let f64_type = context.f64_type();
+ let f64_val = f64_type.const_float(std::f64::consts::PI);
- assert!(module.get_flag("some_key2").is_none());
+ assert!(module.get_flag("some_key2").is_none());
- module.add_basic_value_flag("some_key2", FlagBehavior::Error, f64_val);
+ module.add_basic_value_flag("some_key2", FlagBehavior::Error, f64_val);
- assert!(module.get_flag("some_key2").is_some());
+ assert!(module.get_flag("some_key2").is_some());
- let struct_val = context.const_struct(&[f64_val.into()], false);
+ let struct_val = context.const_struct(&[f64_val.into()], false);
- assert!(module.get_flag("some_key3").is_none());
+ assert!(module.get_flag("some_key3").is_none());
- module.add_basic_value_flag("some_key3", FlagBehavior::Error, struct_val);
+ module.add_basic_value_flag("some_key3", FlagBehavior::Error, struct_val);
- assert!(module.get_flag("some_key3").is_some());
- assert!(module.verify().is_ok());
- }
+ assert!(module.get_flag("some_key3").is_some());
+ assert!(module.verify().is_ok());
}
#[test]
diff --git a/tests/all/test_object_file.rs b/tests/all/test_object_file.rs
index 375a1cd3d67..82449af465f 100644
--- a/tests/all/test_object_file.rs
+++ b/tests/all/test_object_file.rs
@@ -5,12 +5,10 @@ use inkwell::types::IntType;
use inkwell::values::BasicValue;
use inkwell::OptimizationLevel;
-#[llvm_versions(7..)]
fn get_host_cpu_name() -> String {
TargetMachine::get_host_cpu_name().to_string()
}
-#[llvm_versions(7..)]
fn get_host_cpu_features() -> String {
TargetMachine::get_host_cpu_features().to_string()
}
@@ -25,16 +23,6 @@ fn apply_target_to_module(target_machine: &TargetMachine, module: &Module) {
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
}
-#[llvm_versions(..7)]
-fn get_host_cpu_name() -> String {
- "".to_string()
-}
-
-#[llvm_versions(..7)]
-fn get_host_cpu_features() -> String {
- "".to_string()
-}
-
fn get_native_target_machine() -> TargetMachine {
Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target");
let target_triple = TargetMachine::get_default_triple();
@@ -166,7 +154,10 @@ fn test_symbol_iterator() {
"a" => {
assert!(!has_symbol_a);
has_symbol_a = true;
+ #[cfg(unix)]
assert_eq!(symbol.size(), 1);
+ #[cfg(windows)]
+ assert_eq!(symbol.size(), 0);
},
"b" => {
assert!(!has_symbol_b);
diff --git a/tests/all/test_passes.rs b/tests/all/test_passes.rs
index d1138e61362..62df8ba701f 100644
--- a/tests/all/test_passes.rs
+++ b/tests/all/test_passes.rs
@@ -14,10 +14,6 @@ fn test_init_all_passes_for_module() {
let pass_manager = PassManager::create(());
#[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -28,14 +24,7 @@ fn test_init_all_passes_for_module() {
))]
pass_manager.add_argument_promotion_pass();
pass_manager.add_constant_merge_pass();
- #[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0"
- )))]
+ #[cfg(not(any(feature = "llvm8-0", feature = "llvm9-0")))]
pass_manager.add_merge_functions_pass();
pass_manager.add_dead_arg_elimination_pass();
pass_manager.add_function_attrs_pass();
@@ -57,8 +46,6 @@ fn test_init_all_passes_for_module() {
pass_manager.add_internalize_pass(true);
pass_manager.add_strip_dead_prototypes_pass();
pass_manager.add_strip_symbol_pass();
- #[cfg(feature = "llvm4-0")]
- pass_manager.add_bb_vectorize_pass();
pass_manager.add_loop_vectorize_pass();
pass_manager.add_slp_vectorize_pass();
pass_manager.add_aggressive_dce_pass();
@@ -79,10 +66,6 @@ fn test_init_all_passes_for_module() {
pass_manager.add_loop_reroll_pass();
pass_manager.add_loop_unroll_pass();
#[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -130,19 +113,11 @@ fn test_init_all_passes_for_module() {
pass_manager.add_early_cse_mem_ssa_pass();
pass_manager.add_new_gvn_pass();
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm16-0")))]
+ #[cfg(not(feature = "llvm16-0"))]
pass_manager.add_aggressive_inst_combiner_pass();
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
pass_manager.add_loop_unroll_and_jam_pass();
- #[cfg(not(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm15-0",
- feature = "llvm16-0"
- )))]
+ #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0")))]
{
pass_manager.add_coroutine_early_pass();
pass_manager.add_coroutine_split_pass();
@@ -183,10 +158,7 @@ fn test_pass_manager_builder() {
assert!(!fn_pass_manager.initialize());
// TODO: Test with actual changes? Would be true in that case
- // REVIEW: Segfaults in 4.0
- #[cfg(not(feature = "llvm4-0"))]
assert!(!fn_pass_manager.run_on(&fn_value));
-
assert!(!fn_pass_manager.finalize());
let module_pass_manager = PassManager::create(());
@@ -194,10 +166,6 @@ fn test_pass_manager_builder() {
pass_manager_builder.populate_module_pass_manager(&module_pass_manager);
#[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -215,9 +183,6 @@ fn test_pass_manager_builder() {
assert!(lto_pass_manager.run_on(&module2));
}
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0"))]
- assert!(!module_pass_manager.run_on(&module));
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0")))]
assert!(module_pass_manager.run_on(&module));
}
@@ -239,7 +204,7 @@ fn test_pass_registry() {
pass_registry.initialize_ipa();
pass_registry.initialize_codegen();
pass_registry.initialize_target();
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm16-0")))]
+ #[cfg(not(feature = "llvm16-0"))]
pass_registry.initialize_aggressive_inst_combiner();
}
diff --git a/tests/all/test_targets.rs b/tests/all/test_targets.rs
index dad038bdf73..40768fdbf50 100644
--- a/tests/all/test_targets.rs
+++ b/tests/all/test_targets.rs
@@ -27,7 +27,11 @@ fn write_target_machine_to_memory_buffer(target_machine: TargetMachine) {
let string = from_utf8(buffer.as_slice()).unwrap();
- assert!(string.contains(".text"));
+ // Not sure why starting since LLVM 20, text section was removed...
+ #[cfg(not(any(feature = "llvm20-1")))]
+ {
+ assert!(string.contains(".text"));
+ }
assert!(string.contains(".file"));
assert!(string.contains("my_module"));
assert!(string.contains(".section"));
@@ -97,12 +101,6 @@ fn test_target_and_target_machine() {
let bad_target2 = Target::from_triple(&TargetTriple::create("sadas"));
- #[cfg(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm7-0"))]
- assert_eq!(
- bad_target2.unwrap_err().to_string(),
- "No available targets are compatible with this triple."
- );
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm7-0")))]
assert_eq!(
bad_target2.unwrap_err().to_string(),
"No available targets are compatible with triple \"sadas\""
@@ -165,17 +163,14 @@ fn test_target_and_target_machine() {
assert_eq!(target_machine.get_cpu().to_str(), Ok("x86-64"));
assert_eq!(target_machine.get_feature_string().to_str(), Ok("+avx2"));
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- // TODO: Try and find a triple that actually gets normalized..
- assert_eq!(
- TargetMachine::normalize_triple(&triple).as_str().to_str(),
- Ok("x86_64-pc-linux-gnu"),
- );
-
- let _host_name = TargetMachine::get_host_cpu_name();
- let _host_cpu_features = TargetMachine::get_host_cpu_features();
- }
+ // TODO: Try and find a triple that actually gets normalized..
+ assert_eq!(
+ TargetMachine::normalize_triple(&triple).as_str().to_str(),
+ Ok("x86_64-pc-linux-gnu"),
+ );
+
+ let _host_name = TargetMachine::get_host_cpu_name();
+ let _host_cpu_features = TargetMachine::get_host_cpu_features();
}
#[test]
@@ -191,6 +186,8 @@ fn test_default_triple() {
vec!["pc", "unknown", "redhat"]
} else if cfg!(target_os = "macos") {
vec!["apple"]
+ } else if cfg!(target_os = "windows") {
+ vec!["pc", "unknown", "uwp"]
} else {
vec![]
};
@@ -198,13 +195,16 @@ fn test_default_triple() {
let has_known_vendor = vendors.iter().any(|vendor| default_triple.contains(*vendor));
assert!(has_known_vendor, "Target triple '{default_triple}' has unknown vendor");
- let os = [
- #[cfg(target_os = "linux")]
- "linux",
- #[cfg(target_os = "macos")]
- "darwin",
- ];
- let has_known_os = os.iter().any(|os| default_triple.contains(*os));
+ let has_known_os = if cfg!(target_os = "linux") {
+ default_triple.contains("linux")
+ } else if cfg!(target_os = "macos") {
+ default_triple.contains("macos")
+ } else if cfg!(target_os = "windows") {
+ default_triple.contains("windows")
+ } else {
+ false
+ };
+
assert!(has_known_os, "Target triple '{default_triple}' has unknown OS");
// TODO: CFG for other supported major OSes
@@ -401,7 +401,11 @@ fn test_write_target_machine_to_file() {
let string = from_utf8(&contents).unwrap();
- assert!(string.contains(".text"));
+ // Not sure why starting since LLVM 20, text section was removed...
+ #[cfg(not(any(feature = "llvm20-1")))]
+ {
+ assert!(string.contains(".text"));
+ }
assert!(string.contains(".file"));
assert!(string.contains("my_module"));
assert!(string.contains(".section"));
diff --git a/tests/all/test_types.rs b/tests/all/test_types.rs
index 1037984f9ff..3151bf3e5d4 100644
--- a/tests/all/test_types.rs
+++ b/tests/all/test_types.rs
@@ -1,4 +1,5 @@
use inkwell::context::Context;
+use inkwell::memory_buffer::MemoryBuffer;
use inkwell::types::BasicType;
use inkwell::values::AnyValue;
use inkwell::AddressSpace;
@@ -141,6 +142,29 @@ fn test_function_type() {
assert_eq!(fn_type.get_context(), context);
}
+/// Check that `FunctionType::get_param_types()` can handle metadata arguments.
+/// Regression test for inkwell#546
+#[test]
+fn test_function_type_metadata_params() {
+ let llvm_ir = r#"
+ declare void @my_fn(i32, metadata)
+ "#;
+
+ let context = Context::create();
+ let i32_type = context.i32_type();
+ let md_type = context.metadata_type();
+
+ let memory_buffer = MemoryBuffer::create_from_memory_range_copy(llvm_ir.as_bytes(), "my_mod");
+ let module = context.create_module_from_ir(memory_buffer).unwrap();
+
+ let fn_type = module.get_function("my_fn").unwrap().get_type();
+ let param_types = fn_type.get_param_types();
+
+ assert_eq!(param_types.len(), 2);
+ assert_eq!(param_types[0].into_int_type(), i32_type);
+ assert_eq!(param_types[1].into_metadata_type(), md_type);
+}
+
#[test]
fn test_sized_types() {
unsafe { Context::get_global(sized_types) }
@@ -160,12 +184,7 @@ fn sized_types(global_ctx: &Context) {
let f80_type = global_ctx.x86_f80_type();
let f128_type = global_ctx.f128_type();
let ppc_f128_type = global_ctx.ppc_f128_type();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = global_ctx.ptr_type(AddressSpace::default());
let struct_type = global_ctx.struct_type(&[i8_type.into(), f128_type.into()], false);
let struct_type2 = global_ctx.struct_type(&[], false);
@@ -191,12 +210,7 @@ fn sized_types(global_ctx: &Context) {
assert!(f80_type.is_sized());
assert!(f128_type.is_sized());
assert!(ppc_f128_type.is_sized());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
assert!(ptr_type.is_sized());
assert!(struct_type.is_sized());
assert!(struct_type2.is_sized());
@@ -207,12 +221,7 @@ fn sized_types(global_ctx: &Context) {
assert!(!fn_type3.is_sized());
assert!(!fn_type4.is_sized());
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
{
assert!(bool_type.ptr_type(AddressSpace::default()).is_sized());
assert!(i8_type.ptr_type(AddressSpace::default()).is_sized());
@@ -244,12 +253,7 @@ fn sized_types(global_ctx: &Context) {
assert!(f80_type.array_type(42).is_sized());
assert!(f128_type.array_type(42).is_sized());
assert!(ppc_f128_type.array_type(42).is_sized());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
assert!(ptr_type.array_type(42).is_sized());
assert!(struct_type.array_type(0).is_sized());
assert!(struct_type2.array_type(0).is_sized());
@@ -268,12 +272,7 @@ fn sized_types(global_ctx: &Context) {
assert!(f80_type.vec_type(42).is_sized());
assert!(f128_type.vec_type(42).is_sized());
assert!(ppc_f128_type.vec_type(42).is_sized());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
assert!(ptr_type.vec_type(42).is_sized());
#[cfg(any(
@@ -283,7 +282,9 @@ fn sized_types(global_ctx: &Context) {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
{
assert!(bool_type.scalable_vec_type(42).is_sized());
@@ -298,12 +299,7 @@ fn sized_types(global_ctx: &Context) {
assert!(f80_type.scalable_vec_type(42).is_sized());
assert!(f128_type.scalable_vec_type(42).is_sized());
assert!(ppc_f128_type.scalable_vec_type(42).is_sized());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
assert!(ptr_type.scalable_vec_type(42).is_sized());
}
@@ -312,12 +308,7 @@ fn sized_types(global_ctx: &Context) {
assert!(!opaque_struct_type.is_sized());
assert!(!opaque_struct_type.array_type(0).is_sized());
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
{
let opaque_struct_ptr_type = opaque_struct_type.ptr_type(AddressSpace::default());
assert!(opaque_struct_ptr_type.is_sized());
@@ -340,19 +331,9 @@ fn test_const_zero() {
let f128_type = context.f128_type();
let ppc_f128_type = context.ppc_f128_type();
let struct_type = context.struct_type(&[i8_type.into(), f128_type.into()], false);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_type = f64_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
let vec_type = f64_type.vec_type(42);
#[cfg(any(
@@ -362,7 +343,9 @@ fn test_const_zero() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_type = f64_type.scalable_vec_type(42);
let array_type = f64_type.array_type(42);
@@ -379,7 +362,9 @@ fn test_const_zero() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
scalable_vec_type.size_of();
array_type.size_of();
@@ -396,7 +381,9 @@ fn test_const_zero() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
scalable_vec_type.get_alignment();
array_type.get_alignment();
@@ -423,7 +410,9 @@ fn test_const_zero() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_zero = scalable_vec_type.const_zero();
let array_zero = array_type.const_zero();
@@ -450,7 +439,9 @@ fn test_const_zero() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert!(scalable_vec_zero.is_null());
assert!(array_zero.is_null());
@@ -482,12 +473,7 @@ fn test_const_zero() {
);
// handle opaque pointers
- let ptr_type = if cfg!(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )) {
+ let ptr_type = if cfg!(not(feature = "typed-pointers")) {
"ptr null"
} else {
"double* null"
@@ -503,7 +489,9 @@ fn test_const_zero() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert_eq!(
scalable_vec_zero.print_to_string().to_str(),
@@ -515,6 +503,25 @@ fn test_const_zero() {
);
}
+#[test]
+fn test_float_type() {
+ let context = Context::create();
+
+ let f16_type = context.f16_type();
+ let f32_type = context.f32_type();
+ let f64_type = context.f64_type();
+ let f128_type = context.f128_type();
+ let x86_f80_type = context.x86_f80_type();
+ let ppc_f128_type = context.ppc_f128_type();
+
+ assert_eq!(f16_type.get_bit_width(), 16);
+ assert_eq!(f32_type.get_bit_width(), 32);
+ assert_eq!(f64_type.get_bit_width(), 64);
+ assert_eq!(f128_type.get_bit_width(), 128);
+ assert_eq!(x86_f80_type.get_bit_width(), 80);
+ assert_eq!(ppc_f128_type.get_bit_width(), 128);
+}
+
#[test]
fn test_vec_type() {
let context = Context::create();
@@ -546,36 +553,14 @@ fn test_type_copies() {
#[test]
fn test_ptr_type() {
let context = Context::create();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_type = context.i8_type().ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
assert_eq!(ptr_type.get_address_space(), AddressSpace::default());
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
assert_eq!(ptr_type.get_element_type().into_int_type(), context.i8_type());
// Fn ptr:
@@ -584,19 +569,7 @@ fn test_ptr_type() {
#[allow(deprecated)]
let fn_ptr_type = fn_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type);
assert_eq!(fn_ptr_type.get_context(), context);
@@ -615,19 +588,9 @@ fn test_basic_type_enum() {
&context.f64_type(),
// derived types
&int.array_type(0),
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
&int.ptr_type(addr),
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
&context.ptr_type(addr),
&context.struct_type(&[int.as_basic_type_enum()], false),
&int.vec_type(1),
@@ -638,17 +601,14 @@ fn test_basic_type_enum() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
&int.scalable_vec_type(1),
];
for basic_type in types {
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
assert_eq!(
basic_type.as_basic_type_enum().ptr_type(addr),
basic_type.ptr_type(addr)
@@ -684,19 +644,9 @@ fn test_ptr_address_space() {
for index in spaces {
let address_space = AddressSpace::try_from(index).unwrap();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr = context.i32_type().ptr_type(address_space);
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr = context.ptr_type(address_space);
assert_eq!(ptr.get_address_space(), address_space);
}
@@ -711,8 +661,11 @@ fn test_ptr_is_opaque() {
let context = Context::create();
let i32_ptr_type = context.i32_type().ptr_type(AddressSpace::default());
- assert!(i32_ptr_type.is_opaque());
+ assert_eq!(!i32_ptr_type.is_opaque(), cfg!(feature = "typed-pointers"));
- let ptr_type = context.ptr_type(AddressSpace::default());
- assert!(ptr_type.is_opaque());
+ #[cfg(not(feature = "typed-pointers"))]
+ {
+ let ptr_type = context.ptr_type(AddressSpace::default());
+ assert!(ptr_type.is_opaque());
+ }
}
diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs
index 72fa704b5d6..65c7364e8f5 100644
--- a/tests/all/test_values.rs
+++ b/tests/all/test_values.rs
@@ -1,18 +1,20 @@
use inkwell::attributes::AttributeLoc;
-#[llvm_versions(7..)]
+
use inkwell::comdat::ComdatSelectionKind;
use inkwell::context::Context;
+#[llvm_versions(15..)]
+use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::Linkage::*;
use inkwell::types::{AnyTypeEnum, StringRadix, VectorType};
+#[llvm_versions(15..)]
+use inkwell::values::CallSiteValue;
#[llvm_versions(18..)]
use inkwell::values::OperandBundle;
use inkwell::values::{AnyValue, InstructionOpcode::*, FIRST_CUSTOM_METADATA_KIND_ID};
use inkwell::{AddressSpace, DLLStorageClass, GlobalVisibility, ThreadLocalMode};
#[llvm_versions(18..)]
-pub use llvm_sys::LLVMTailCallKind::*;
-#[cfg(feature = "llvm18-0")]
-use llvm_sys_180 as llvm_sys;
+pub use inkwell::llvm_sys::LLVMTailCallKind::*;
use std::convert::TryFrom;
@@ -72,7 +74,7 @@ fn test_call_site() {
}
#[test]
-#[cfg(feature = "llvm18-0")]
+#[cfg(any(feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1"))]
fn test_call_site_tail_call_attributes() {
let context = Context::create();
let builder = context.create_builder();
@@ -147,6 +149,53 @@ fn test_call_site_operand_bundles() {
args_iter.for_each(|arg| assert!(arg.into_int_value().is_const()));
}
+/// Check that `CallSiteValue::get_called_fn_value` returns `None` if the underlying call is indirect.
+/// Regression test for inkwell#571.
+/// Restricted to LLVM >= 15, since the input IR uses opaque pointers.
+#[llvm_versions(15..)]
+#[test]
+fn test_call_site_function_value_indirect_call() {
+ // ```c
+ // void dummy_fn();
+ //
+ // void my_fn() {
+ // void (*fn_ptr)(void) = &dummy_fn;
+ // (*fn_ptr)();
+ // }
+ // ```
+
+ let llvm_ir = r#"
+ source_filename = "my_mod";
+
+ define void @my_fn() {
+ entry:
+ %0 = alloca ptr, align 8
+ store ptr @dummy_fn, ptr %0, align 8
+ %1 = load ptr, ptr %0, align 8
+ call void %1()
+ ret void
+ }
+
+ declare void @dummy_fn();
+ "#;
+
+ let memory_buffer = MemoryBuffer::create_from_memory_range_copy(llvm_ir.as_bytes(), "my_mod");
+ let context = Context::create();
+ let module = context.create_module_from_ir(memory_buffer).unwrap();
+
+ let main_fn = module.get_function("my_fn").unwrap();
+ let inst = main_fn
+ .get_last_basic_block()
+ .unwrap()
+ .get_instructions()
+ .nth(3)
+ .unwrap();
+ let call_site_value = CallSiteValue::try_from(inst).unwrap();
+
+ let fn_value = call_site_value.get_called_fn_value();
+ assert!(fn_value.is_none());
+}
+
#[test]
fn test_set_get_name() {
let context = Context::create();
@@ -160,12 +209,7 @@ fn test_set_get_name() {
let f32_type = context.f32_type();
let f64_type = context.f64_type();
let f128_type = context.f128_type();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
let array_type = f64_type.array_type(42);
let ppc_f128_type = context.ppc_f128_type();
@@ -180,19 +224,9 @@ fn test_set_get_name() {
let f32_val = f32_type.const_float(0.0);
let f64_val = f64_type.const_float(0.0);
let f128_val = f128_type.const_float(0.0);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_val = bool_type.ptr_type(AddressSpace::default()).const_null();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_val = ptr_type.const_null();
let array_val = f64_type.const_array(&[f64_val]);
let struct_val = context.const_struct(&[i8_val.into(), f128_val.into()], false);
@@ -204,7 +238,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_val = f64_type.scalable_vec_type(42).const_zero();
let ppc_f128_val = ppc_f128_type.const_float(0.0);
@@ -230,7 +266,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert_eq!(scalable_vec_val.get_name().to_str(), Ok(""));
assert_eq!(ppc_f128_val.get_name().to_str(), Ok(""));
@@ -257,7 +295,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
scalable_vec_val.set_name("my_val15");
ppc_f128_val.set_name("my_val16");
@@ -283,25 +323,17 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert_eq!(scalable_vec_val.get_name().to_str(), Ok(""));
assert_eq!(ppc_f128_val.get_name().to_str(), Ok(""));
let void_type = context.void_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_type = bool_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
let struct_type = context.struct_type(&[bool_type.into()], false);
let vec_type = bool_type.vec_type(1);
@@ -312,7 +344,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_type = bool_type.scalable_vec_type(1);
@@ -334,7 +368,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
scalable_vec_type.into(),
];
@@ -358,7 +394,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_param = function.get_nth_param(6).unwrap().into_scalable_vector_value();
let phi_val = builder.build_phi(bool_type, "phi_node").unwrap();
@@ -376,7 +414,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert_eq!(scalable_vec_param.get_name().to_str(), Ok(""));
assert_eq!(phi_val.get_name().to_str(), Ok("phi_node"));
@@ -394,7 +434,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
scalable_vec_param.set_name("my_val7");
phi_val.set_name("phi");
@@ -412,7 +454,9 @@ fn test_set_get_name() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert_eq!(scalable_vec_param.get_name().to_str(), Ok("my_val7"));
assert_eq!(phi_val.get_name().to_str(), Ok("phi"));
@@ -433,12 +477,7 @@ fn test_undef() {
let f32_type = context.f32_type();
let f64_type = context.f64_type();
let f128_type = context.f128_type();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
let array_type = f64_type.array_type(42);
let ppc_f128_type = context.ppc_f128_type();
@@ -455,19 +494,9 @@ fn test_undef() {
let f32_val = f32_type.const_float(0.0);
let f64_val = f64_type.const_float(0.0);
let f128_val = f128_type.const_float(0.0);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_val = bool_type.ptr_type(AddressSpace::default()).const_null();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_val = ptr_type.const_null();
let array_val = f64_type.const_array(&[f64_val]);
let struct_val = context.const_struct(&[i8_val.into(), f128_val.into()], false);
@@ -479,7 +508,9 @@ fn test_undef() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_val = f64_type.scalable_vec_type(42).const_zero();
let ppc_f128_val = ppc_f128_type.const_float(0.0);
@@ -505,7 +536,9 @@ fn test_undef() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert!(!scalable_vec_val.is_undef());
assert!(!ppc_f128_val.is_undef());
@@ -520,19 +553,9 @@ fn test_undef() {
let f32_undef = f32_type.get_undef();
let f64_undef = f64_type.get_undef();
let f128_undef = f128_type.get_undef();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_undef = bool_type.ptr_type(AddressSpace::default()).get_undef();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_undef = ptr_type.get_undef();
let array_undef = array_type.get_undef();
let struct_undef = context.struct_type(&[bool_type.into()], false).get_undef();
@@ -544,7 +567,9 @@ fn test_undef() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_undef = bool_type.scalable_vec_type(1).get_undef();
let ppc_f128_undef = ppc_f128_type.get_undef();
@@ -570,7 +595,9 @@ fn test_undef() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert!(scalable_vec_undef.is_undef());
assert!(ppc_f128_undef.is_undef());
@@ -590,12 +617,7 @@ fn test_poison() {
let f32_type = context.f32_type();
let f64_type = context.f64_type();
let f128_type = context.f128_type();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_type = context.ptr_type(AddressSpace::default());
let array_type = f64_type.array_type(42);
#[cfg(any(
@@ -605,7 +627,9 @@ fn test_poison() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_type = f64_type.scalable_vec_type(42);
let ppc_f128_type = context.ppc_f128_type();
@@ -622,19 +646,9 @@ fn test_poison() {
let f32_val = f32_type.const_float(0.0);
let f64_val = f64_type.const_float(0.0);
let f128_val = f128_type.const_float(0.0);
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_val = bool_type.ptr_type(AddressSpace::default()).const_null();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_val = ptr_type.const_null();
let array_val = f64_type.const_array(&[f64_val]);
let struct_val = context.const_struct(&[i8_val.into(), f128_val.into()], false);
@@ -646,7 +660,9 @@ fn test_poison() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_val = scalable_vec_type.const_zero();
let ppc_f128_val = ppc_f128_type.const_float(0.0);
@@ -672,7 +688,9 @@ fn test_poison() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert!(!scalable_vec_val.is_poison());
assert!(!ppc_f128_val.is_poison());
@@ -687,19 +705,9 @@ fn test_poison() {
let f32_poison = f32_type.get_poison();
let f64_poison = f64_type.get_poison();
let f128_poison = f128_type.get_poison();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let ptr_poison = bool_type.ptr_type(AddressSpace::default()).get_poison();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let ptr_poison = ptr_type.get_poison();
let array_poison = array_type.get_poison();
let struct_poison = context.struct_type(&[bool_type.into()], false).get_poison();
@@ -711,7 +719,9 @@ fn test_poison() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_poison = scalable_vec_type.get_poison();
let ppc_f128_poison = ppc_f128_type.get_poison();
@@ -737,7 +747,9 @@ fn test_poison() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert!(scalable_vec_poison.is_poison());
assert!(ppc_f128_poison.is_poison());
@@ -827,166 +839,159 @@ fn test_metadata() {
assert_eq!(context.get_kind_id("type"), 19);
assert_eq!(context.get_kind_id("section_prefix"), 20);
assert_eq!(context.get_kind_id("absolute_symbol"), 21);
+ assert_eq!(context.get_kind_id("associated"), 22);
+ assert_eq!(context.get_kind_id("callees"), 23);
+ assert_eq!(context.get_kind_id("irr_loop"), 24);
+ assert_eq!(module.get_global_metadata_size("my_string_md"), 0);
+ assert_eq!(module.get_global_metadata("my_string_md").len(), 0);
- #[cfg(not(feature = "llvm4-0"))]
- {
- assert_eq!(context.get_kind_id("associated"), 22);
- }
+ let md_string = context.metadata_string("lots of metadata here");
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0")))]
- {
- assert_eq!(context.get_kind_id("callees"), 23);
- assert_eq!(context.get_kind_id("irr_loop"), 24);
- }
+ assert_eq!(md_string.get_node_size(), 0);
+ assert_eq!(md_string.get_node_values().len(), 0);
+ assert_eq!(
+ md_string.get_string_value().unwrap().to_str(),
+ Ok("lots of metadata here")
+ );
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- assert_eq!(module.get_global_metadata_size("my_string_md"), 0);
- assert_eq!(module.get_global_metadata("my_string_md").len(), 0);
-
- let md_string = context.metadata_string("lots of metadata here");
-
- assert_eq!(md_string.get_node_size(), 0);
- assert_eq!(md_string.get_node_values().len(), 0);
- assert_eq!(
- md_string.get_string_value().unwrap().to_str(),
- Ok("lots of metadata here")
- );
-
- let bool_type = context.bool_type();
- // let i8_type = context.i8_type();
- // let i16_type = context.i16_type();
- // let i32_type = context.i32_type();
- // let i64_type = context.i64_type();
- // let i128_type = context.i128_type();
- // let f16_type = context.f16_type();
- let f32_type = context.f32_type();
- // let f64_type = context.f64_type();
- // let f128_type = context.f128_type();
- // #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
- // let ptr_type = context.ptr_type(AddressSpace::default());
- // let array_type = f64_type.array_type(42);
- // let ppc_f128_type = context.ppc_f128_type();
- // let fn_type = bool_type.fn_type(&[i64_type.into(), array_type.into()], false);
-
- let bool_val = bool_type.const_int(0, false);
- // let i8_val = i8_type.const_int(0, false);
- // let i16_val = i16_type.const_int(0, false);
- // let i32_val = i32_type.const_int(0, false);
- // let i64_val = i64_type.const_int(0, false);
- // let i128_val = i128_type.const_int(0, false);
- // let f16_val = f16_type.const_float(0.0);
- let f32_val = f32_type.const_float(0.0);
- // let f64_val = f64_type.const_float(0.0);
- // let f128_val = f128_type.const_float(0.0);
- // let ppc_f128_val = ppc_f128_type.const_float(0.0);
- // #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
- // let ptr_val = bool_type.ptr_type(AddressSpace::default()).const_null();
- // #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
- // let ptr_val = ptr_type.const_null();
- // let array_val = f64_type.const_array(&[f64_val]);
- // let struct_val = context.const_struct(&[i8_val.into(), f128_val.into()], false);
- // let vec_val = VectorType::const_vector(&[i8_val]);
- // let fn_val = module.add_function("my_fn", fn_type, None);
-
- let md_node_child = context.metadata_node(&[bool_val.into(), f32_val.into()]);
- let md_node = context.metadata_node(&[bool_val.into(), f32_val.into(), md_string.into(), md_node_child.into()]);
-
- let node_values = md_node.get_node_values();
-
- assert_eq!(md_node.get_string_value(), None);
- assert_eq!(node_values.len(), 4);
- assert_eq!(node_values[0].into_int_value(), bool_val);
- assert_eq!(node_values[1].into_float_value(), f32_val);
- assert_eq!(
- node_values[2].into_metadata_value().get_string_value(),
- md_string.get_string_value()
- );
- assert!(node_values[3].into_metadata_value().is_node());
-
- assert!(module.add_global_metadata("my_md", &md_string).is_err());
- module.add_global_metadata("my_md", &md_node).unwrap();
-
- assert_eq!(module.get_global_metadata_size("my_md"), 1);
-
- let global_md = module.get_global_metadata("my_md");
-
- assert_eq!(global_md.len(), 1);
-
- let md = global_md[0].get_node_values();
-
- assert_eq!(md.len(), 4);
- assert_eq!(md[0].into_int_value(), bool_val);
- assert_eq!(md[1].into_float_value(), f32_val);
- assert_eq!(
- md[2].into_metadata_value().get_string_value(),
- md_string.get_string_value()
- );
- assert!(md[3].into_metadata_value().is_node());
-
- assert_eq!(module.get_global_metadata_size("other_md"), 0);
-
- // REVIEW: const_null_ptr/ ptr.const_null seem to cause UB. Need to test and adapt
- // and see if they should be allowed to have metadata? Also, while we're at it we should
- // try with undef
-
- // REVIEW: initial has_metadata seems inconsistent. Some have it. Some don't for kind_id 0. Some sometimes have it.
- // furthermore, when they do have it, it is a SF when printing out. Unclear what can be done here. Maybe just disallow index 0?
- // assert!(bool_val.has_metadata());
- // assert!(i8_val.has_metadata());
- // assert!(i16_val.has_metadata());
- // assert!(i32_val.has_metadata());
- // assert!(i64_val.has_metadata());
- // assert!(!i128_val.has_metadata());
- // assert!(!f16_val.has_metadata());
- // assert!(!f32_val.has_metadata());
- // assert!(!f64_val.has_metadata());
- // assert!(!f128_val.has_metadata());
- // assert!(!ppc_f128_val.has_metadata());
- // assert!(ptr_val.has_metadata());
- // assert!(array_val.has_metadata());
- // assert!(struct_val.has_metadata());
- // assert!(!vec_val.has_metadata());
- // assert!(!fn_val.has_metadata());
-
- let builder = context.create_builder();
- let module = context.create_module("my_mod");
- let void_type = context.void_type();
- let bool_type = context.bool_type();
- let fn_type = void_type.fn_type(&[bool_type.into()], false);
- let fn_value = module.add_function("my_func", fn_type, None);
-
- let entry_block = context.append_basic_block(fn_value, "entry");
-
- builder.position_at_end(entry_block);
-
- let ret_instr = builder.build_return(None).unwrap();
- let ret_instr_md = context.metadata_node(&[md_string.into()]);
-
- assert!(ret_instr.set_metadata(ret_instr_md, 2).is_ok());
- assert!(ret_instr.has_metadata());
- assert!(ret_instr.get_metadata(1).is_none());
-
- let md_node_values = ret_instr.get_metadata(2).unwrap().get_node_values();
-
- assert_eq!(md_node_values.len(), 1);
- assert_eq!(
- md_node_values[0].into_metadata_value().get_string_value(),
- md_string.get_string_value()
- );
-
- // New Context Metadata
- let context_metadata_node = context.metadata_node(&[bool_val.into(), f32_val.into()]);
- let context_metadata_string = context.metadata_string("my_context_metadata");
-
- assert!(context_metadata_node.is_node());
- assert!(context_metadata_string.is_string());
- }
+ let bool_type = context.bool_type();
+ // let i8_type = context.i8_type();
+ // let i16_type = context.i16_type();
+ // let i32_type = context.i32_type();
+ // let i64_type = context.i64_type();
+ // let i128_type = context.i128_type();
+ // let f16_type = context.f16_type();
+ let f32_type = context.f32_type();
+ // let f64_type = context.f64_type();
+ // let f128_type = context.f128_type();
+ // #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1"))]
+ // let ptr_type = context.ptr_type(AddressSpace::default());
+ // let array_type = f64_type.array_type(42);
+ // let ppc_f128_type = context.ppc_f128_type();
+ // let fn_type = bool_type.fn_type(&[i64_type.into(), array_type.into()], false);
+
+ let bool_val = bool_type.const_int(0, false);
+ // let i8_val = i8_type.const_int(0, false);
+ // let i16_val = i16_type.const_int(0, false);
+ // let i32_val = i32_type.const_int(0, false);
+ // let i64_val = i64_type.const_int(0, false);
+ // let i128_val = i128_type.const_int(0, false);
+ // let f16_val = f16_type.const_float(0.0);
+ let f32_val = f32_type.const_float(0.0);
+ // let f64_val = f64_type.const_float(0.0);
+ // let f128_val = f128_type.const_float(0.0);
+ // let ppc_f128_val = ppc_f128_type.const_float(0.0);
+ // #[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1")))]
+ // let ptr_val = bool_type.ptr_type(AddressSpace::default()).const_null();
+ // #[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-1", feature = "llvm19-1", feature = "llvm20-1"))]
+ // let ptr_val = ptr_type.const_null();
+ // let array_val = f64_type.const_array(&[f64_val]);
+ // let struct_val = context.const_struct(&[i8_val.into(), f128_val.into()], false);
+ // let vec_val = VectorType::const_vector(&[i8_val]);
+ // let fn_val = module.add_function("my_fn", fn_type, None);
+
+ let md_node_child = context.metadata_node(&[bool_val.into(), f32_val.into()]);
+ let md_node = context.metadata_node(&[bool_val.into(), f32_val.into(), md_string.into(), md_node_child.into()]);
+
+ let node_values = md_node.get_node_values();
+
+ assert_eq!(md_node.get_string_value(), None);
+ assert_eq!(node_values.len(), 4);
+ assert_eq!(node_values[0].into_int_value(), bool_val);
+ assert_eq!(node_values[1].into_float_value(), f32_val);
+ assert_eq!(
+ node_values[2].into_metadata_value().get_string_value(),
+ md_string.get_string_value()
+ );
+ assert!(node_values[3].into_metadata_value().is_node());
+
+ assert!(module.add_global_metadata("my_md", &md_string).is_err());
+ module.add_global_metadata("my_md", &md_node).unwrap();
+
+ assert_eq!(module.get_global_metadata_size("my_md"), 1);
+
+ let global_md = module.get_global_metadata("my_md");
+
+ assert_eq!(global_md.len(), 1);
+
+ let md = global_md[0].get_node_values();
+
+ assert_eq!(md.len(), 4);
+ assert_eq!(md[0].into_int_value(), bool_val);
+ assert_eq!(md[1].into_float_value(), f32_val);
+ assert_eq!(
+ md[2].into_metadata_value().get_string_value(),
+ md_string.get_string_value()
+ );
+ assert!(md[3].into_metadata_value().is_node());
+
+ assert_eq!(module.get_global_metadata_size("other_md"), 0);
+
+ // REVIEW: const_null_ptr/ ptr.const_null seem to cause UB. Need to test and adapt
+ // and see if they should be allowed to have metadata? Also, while we're at it we should
+ // try with undef
+
+ // REVIEW: initial has_metadata seems inconsistent. Some have it. Some don't for kind_id 0. Some sometimes have it.
+ // furthermore, when they do have it, it is a SF when printing out. Unclear what can be done here. Maybe just disallow index 0?
+ // assert!(bool_val.has_metadata());
+ // assert!(i8_val.has_metadata());
+ // assert!(i16_val.has_metadata());
+ // assert!(i32_val.has_metadata());
+ // assert!(i64_val.has_metadata());
+ // assert!(!i128_val.has_metadata());
+ // assert!(!f16_val.has_metadata());
+ // assert!(!f32_val.has_metadata());
+ // assert!(!f64_val.has_metadata());
+ // assert!(!f128_val.has_metadata());
+ // assert!(!ppc_f128_val.has_metadata());
+ // assert!(ptr_val.has_metadata());
+ // assert!(array_val.has_metadata());
+ // assert!(struct_val.has_metadata());
+ // assert!(!vec_val.has_metadata());
+ // assert!(!fn_val.has_metadata());
+
+ let builder = context.create_builder();
+ let module = context.create_module("my_mod");
+ let void_type = context.void_type();
+ let bool_type = context.bool_type();
+ let fn_type = void_type.fn_type(&[bool_type.into()], false);
+ let fn_value = module.add_function("my_func", fn_type, None);
+
+ let entry_block = context.append_basic_block(fn_value, "entry");
+
+ builder.position_at_end(entry_block);
+
+ let ret_instr = builder.build_return(None).unwrap();
+ let ret_instr_md = context.metadata_node(&[md_string.into()]);
+
+ assert!(ret_instr.set_metadata(ret_instr_md, 2).is_ok());
+ assert!(ret_instr.has_metadata());
+ assert!(ret_instr.get_metadata(1).is_none());
+
+ let md_node_values = ret_instr.get_metadata(2).unwrap().get_node_values();
+
+ assert_eq!(md_node_values.len(), 1);
+ assert_eq!(
+ md_node_values[0].into_metadata_value().get_string_value(),
+ md_string.get_string_value()
+ );
+
+ // New Context Metadata
+ let context_metadata_node = context.metadata_node(&[bool_val.into(), f32_val.into()]);
+ let context_metadata_string = context.metadata_string("my_context_metadata");
+
+ assert!(context_metadata_node.is_node());
+ assert!(context_metadata_string.is_string());
}
#[test]
fn test_floats() {
- #[cfg(not(any(feature = "llvm15-0", feature = "llvm18-0")))]
+ #[cfg(not(any(
+ feature = "llvm15-0",
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
+ )))]
{
use inkwell::FloatPredicate;
@@ -1011,7 +1016,7 @@ fn test_floats() {
assert_eq!(f128_pi.get_type(), f128_type);
assert_eq!(f128_pi_cast.get_type(), f128_type);
- // REIVEW: Why are these not FPTrunc, FPExt, FPToSI, FPToUI, BitCast instructions?
+ // REVIEW: Why are these not FPTrunc, FPExt, FPToSI, FPToUI, BitCast instructions?
// Only thing I can think of is that they're constants and therefore precalculated
assert!(f32_pi.as_instruction().is_none());
assert!(f128_pi.as_instruction().is_none());
@@ -1021,7 +1026,13 @@ fn test_floats() {
let f64_one = f64_type.const_float(1.);
let f64_two = f64_type.const_float(2.);
- #[cfg(not(any(feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
+ #[cfg(not(any(
+ feature = "llvm16-0",
+ feature = "llvm17-0",
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
+ )))]
{
let neg_two = f64_two.const_neg();
@@ -1165,7 +1176,6 @@ fn test_global_byte_array() {
#[test]
fn test_globals() {
- #[llvm_versions(7..)]
use inkwell::values::UnnamedAddress;
let context = Context::create();
@@ -1179,7 +1189,6 @@ fn test_globals() {
let global = module.add_global(i8_type, None, "my_global");
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
assert_eq!(global.get_unnamed_address(), UnnamedAddress::None);
assert!(global.get_previous_global().is_none());
assert!(global.get_next_global().is_none());
@@ -1195,7 +1204,6 @@ fn test_globals() {
assert_eq!(global.get_dll_storage_class(), DLLStorageClass::default());
assert_eq!(global.get_visibility(), GlobalVisibility::default());
assert_eq!(global.get_linkage(), External);
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm7-0")))]
assert_eq!(global.get_value_type(), AnyTypeEnum::IntType(i8_type));
assert_eq!(module.get_first_global().unwrap(), global);
assert_eq!(module.get_last_global().unwrap(), global);
@@ -1207,7 +1215,6 @@ fn test_globals() {
assert!(module.get_global("my_global").is_none());
assert_eq!(module.get_global("glob").unwrap(), global);
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
global.set_unnamed_address(UnnamedAddress::Local);
global.set_dll_storage_class(DLLStorageClass::Import);
global.set_initializer(&i8_zero);
@@ -1218,7 +1225,6 @@ fn test_globals() {
global.set_section(Some("not sure what goes here"));
// REVIEW: Not sure why this is Global when we set it to Local
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
assert_eq!(global.get_unnamed_address(), UnnamedAddress::Global);
assert_eq!(global.get_dll_storage_class(), DLLStorageClass::Import);
assert_eq!(global.get_initializer().unwrap().into_int_value(), i8_zero);
@@ -1243,14 +1249,12 @@ fn test_globals() {
assert_eq!(global.get_linkage(), Private);
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
global.set_unnamed_address(UnnamedAddress::Global);
global.set_dll_storage_class(DLLStorageClass::Export);
global.set_thread_local(false);
global.set_linkage(External);
global.set_visibility(GlobalVisibility::Protected);
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
assert_eq!(global.get_unnamed_address(), UnnamedAddress::Global);
assert!(!global.is_thread_local());
assert_eq!(global.get_visibility(), GlobalVisibility::Protected);
@@ -1302,23 +1306,20 @@ fn test_globals() {
// REVIEW: This doesn't seem to work. LLVM bug?
assert!(global2.is_externally_initialized());
- #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
- {
- assert!(global.get_comdat().is_none());
+ assert!(global.get_comdat().is_none());
- let comdat = module.get_or_insert_comdat("my_comdat");
+ let comdat = module.get_or_insert_comdat("my_comdat");
- assert!(global.get_comdat().is_none());
+ assert!(global.get_comdat().is_none());
- global.set_comdat(comdat);
+ global.set_comdat(comdat);
- assert_eq!(comdat, global.get_comdat().unwrap());
- assert_eq!(comdat.get_selection_kind(), ComdatSelectionKind::Any);
+ assert_eq!(comdat, global.get_comdat().unwrap());
+ assert_eq!(comdat.get_selection_kind(), ComdatSelectionKind::Any);
- comdat.set_selection_kind(ComdatSelectionKind::Largest);
+ comdat.set_selection_kind(ComdatSelectionKind::Largest);
- assert_eq!(comdat.get_selection_kind(), ComdatSelectionKind::Largest);
- }
+ assert_eq!(comdat.get_selection_kind(), ComdatSelectionKind::Largest);
unsafe {
global.delete();
@@ -1400,12 +1401,7 @@ fn test_allocations() {
builder.position_at_end(entry_block);
// handle opaque pointers
- let ptr_type = if cfg!(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )) {
+ let ptr_type = if cfg!(not(feature = "typed-pointers")) {
"ptr"
} else {
"i32*"
@@ -1462,6 +1458,7 @@ fn test_string_values() {
let i8_type = context.i8_type();
let string = context.const_string(b"my_string", false);
let string_null = context.const_string(b"my_string", true);
+ let string_internal_nul = context.const_string(b"my\0string", false);
assert!(string.is_const());
assert!(string_null.is_const());
@@ -1476,27 +1473,32 @@ fn test_string_values() {
assert_eq!(string.get_type().get_element_type().into_int_type(), i8_type);
assert_eq!(string_null.get_type().get_element_type().into_int_type(), i8_type);
- let string_const = string.get_string_constant();
- let string_null_const = string_null.get_string_constant();
+ let string_const = string.as_const_string();
+ let string_null_const = string_null.as_const_string();
+ let string_internal_nul_const = string_internal_nul.as_const_string();
assert!(string_const.is_some());
assert!(string_null_const.is_some());
- assert_eq!(string_const.unwrap().to_str(), Ok("my_string"));
- assert_eq!(string_null_const.unwrap().to_str(), Ok("my_string"));
+ assert_eq!(string_const.unwrap(), b"my_string");
+ assert_eq!(string_null_const.unwrap(), b"my_string\0");
+ assert_eq!(string_internal_nul_const.unwrap(), b"my\0string");
let i8_val = i8_type.const_int(33, false);
let i8_val2 = i8_type.const_int(43, false);
let non_string_vec_i8 = i8_type.const_array(&[i8_val, i8_val2]);
- let non_string_vec_i8_const = non_string_vec_i8.get_string_constant();
+ let non_string_vec_i8_const = non_string_vec_i8.as_const_string();
// TODOC: Will still interpret vec as string even if not generated with const_string:
assert!(non_string_vec_i8_const.is_some());
- assert_eq!(non_string_vec_i8_const.unwrap().to_str(), Ok("!+"));
+ assert_eq!(non_string_vec_i8_const.unwrap(), b"!+");
let i32_type = context.i32_type();
let i32_val = i32_type.const_int(33, false);
let i32_val2 = i32_type.const_int(43, false);
let non_string_vec_i32 = i8_type.const_array(&[i32_val, i32_val2, i32_val2]);
+
+ // This test expects silent truncation
+ #[allow(deprecated)]
let non_string_vec_i32_const = non_string_vec_i32.get_string_constant();
// TODOC: Will still interpret vec with non i8 but in unexpected ways:
@@ -1540,7 +1542,9 @@ fn test_consts() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
let scalable_vec_val = f64_type.scalable_vec_type(42).const_zero();
let array_val = i8_type.const_array(&[i8_val]);
@@ -1565,7 +1569,9 @@ fn test_consts() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
assert!(scalable_vec_val.is_const());
assert!(array_val.is_const());
@@ -1691,19 +1697,9 @@ fn test_non_fn_ptr_called() {
let builder = context.create_builder();
let module = context.create_module("my_mod");
let i8_type = context.i8_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i8_ptr_type = i8_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = i8_type.fn_type(&[i8_ptr_type.into()], false);
let fn_value = module.add_function("my_func", fn_type, None);
@@ -1712,10 +1708,6 @@ fn test_non_fn_ptr_called() {
builder.position_at_end(bb);
#[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
@@ -1733,7 +1725,9 @@ fn test_non_fn_ptr_called() {
feature = "llvm15-0",
feature = "llvm16-0",
feature = "llvm17-0",
- feature = "llvm18-0"
+ feature = "llvm18-1",
+ feature = "llvm19-1",
+ feature = "llvm20-1"
))]
builder
.build_indirect_call(i8_ptr_type.fn_type(&[], false), i8_ptr_param, &[], "call")
@@ -1806,19 +1800,9 @@ fn test_aggregate_returns() {
let builder = context.create_builder();
let module = context.create_module("my_mod");
let i32_type = context.i32_type();
- #[cfg(not(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- )))]
+ #[cfg(feature = "typed-pointers")]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let i32_three = i32_type.const_int(3, false);
let i32_seven = i32_type.const_int(7, false);
@@ -1830,26 +1814,9 @@ fn test_aggregate_returns() {
let ptr_param2 = fn_value.get_nth_param(1).unwrap().into_pointer_value();
builder.position_at_end(bb);
- #[cfg(any(
- feature = "llvm4-0",
- feature = "llvm5-0",
- feature = "llvm6-0",
- feature = "llvm7-0",
- feature = "llvm8-0",
- feature = "llvm9-0",
- feature = "llvm10-0",
- feature = "llvm11-0",
- feature = "llvm12-0",
- feature = "llvm13-0",
- feature = "llvm14-0"
- ))]
+ #[cfg(feature = "typed-pointers")]
builder.build_ptr_diff(ptr_param1, ptr_param2, "diff").unwrap();
- #[cfg(any(
- feature = "llvm15-0",
- feature = "llvm16-0",
- feature = "llvm17-0",
- feature = "llvm18-0"
- ))]
+ #[cfg(not(feature = "typed-pointers"))]
builder
.build_ptr_diff(i32_ptr_type, ptr_param1, ptr_param2, "diff")
.unwrap();