From 3a97796d74e44fa5e4c60dcba3ac7dade93bcf0d Mon Sep 17 00:00:00 2001 From: AdityaK <110843012+aditya-solana@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:12:12 -0700 Subject: [PATCH 01/34] Support llvm-15 for inkwell --- Cargo.toml | 3 +++ src/lib.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1d075696a8d..d3908aa91e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ llvm11-0 = ["llvm-sys-110"] llvm12-0 = ["llvm-sys-120"] llvm13-0 = ["llvm-sys-130"] llvm14-0 = ["llvm-sys-140"] +llvm15-0 = ["llvm-sys-150"] # Don't link aganist 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 @@ -41,6 +42,7 @@ llvm11-0-no-llvm-linking = ["llvm11-0", "llvm-sys-110/no-llvm-linking"] llvm12-0-no-llvm-linking = ["llvm12-0", "llvm-sys-120/no-llvm-linking"] llvm13-0-no-llvm-linking = ["llvm13-0", "llvm-sys-130/no-llvm-linking"] 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"] # Don't force linking to libffi on non-windows platforms. Without this feature # inkwell always links to libffi on non-windows platforms. no-libffi-linking = [] @@ -97,6 +99,7 @@ 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.0", optional = true } once_cell = "1.4.1" parking_lot = "0.12" static-alloc = { version = "0.2", optional = true } diff --git a/src/lib.rs b/src/lib.rs index f60014bf4c6..764d7789722 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,8 @@ extern crate llvm_sys_120 as llvm_sys; extern crate llvm_sys_130 as llvm_sys; #[cfg(feature = "llvm14-0")] extern crate llvm_sys_140 as llvm_sys; +#[cfg(feature = "llvm15-0")] +extern crate llvm_sys_150 as llvm_sys; #[cfg(feature = "llvm4-0")] extern crate llvm_sys_40 as llvm_sys; #[cfg(feature = "llvm5-0")] @@ -103,7 +105,7 @@ macro_rules! assert_unique_used_features { } } -assert_unique_used_features! {"llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8-0", "llvm9-0", "llvm10-0", "llvm11-0", "llvm12-0", "llvm13-0", "llvm14-0"} +assert_unique_used_features! {"llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8-0", "llvm9-0", "llvm10-0", "llvm11-0", "llvm12-0", "llvm13-0", "llvm14-0", "llvm15-0"} /// Defines the address space in which a global will be inserted. /// From fffe5769cc12252fddc12acef02fcf5935d3ed00 Mon Sep 17 00:00:00 2001 From: AdityaK <110843012+aditya-solana@users.noreply.github.com> Date: Tue, 1 Nov 2022 07:55:56 -0700 Subject: [PATCH 02/34] Add llvm15-0 to supported features --- .github/workflows/test.yml | 5 +++-- Cargo.toml | 2 +- internal_macros/src/lib.rs | 4 ++-- src/debug_info.rs | 21 ++++++++++++++------- src/module.rs | 12 ++++++++---- src/types/enums.rs | 16 ++++++++++------ src/values/metadata_value.rs | 2 +- 7 files changed, 39 insertions(+), 23 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5aa17283cc8..1a96c840a50 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,8 +4,8 @@ on: [push, pull_request] env: CARGO_TERM_COLOR: always - DOC_LLVM_FEATURE: llvm14-0 - DOC_LLVM_VERSION: '14.0' + DOC_LLVM_FEATURE: llvm15-0 + DOC_LLVM_VERSION: '15.0' DOC_PATH: target/doc jobs: @@ -27,6 +27,7 @@ jobs: - ["12.0", "12-0"] - ["13.0", "13-0"] - ["14.0", "14-0"] + - ["15.0", "15-0"] steps: - name: Checkout Repo uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index d3908aa91e4..a459a52906d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,7 @@ 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.0", optional = true } +llvm-sys-150 = { package = "llvm-sys", version = "150.0.3", optional = true } once_cell = "1.4.1" parking_lot = "0.12" static-alloc = { version = "0.2", optional = true } diff --git a/internal_macros/src/lib.rs b/internal_macros/src/lib.rs index 7e99f343105..95f602abfed 100644 --- a/internal_macros/src/lib.rs +++ b/internal_macros/src/lib.rs @@ -12,9 +12,9 @@ use syn::{parenthesized, parse_macro_input, parse_quote}; use syn::{Attribute, Field, Ident, Item, LitFloat, Token, Variant}; // This array should match the LLVM features in the top level Cargo manifest -const FEATURE_VERSIONS: [&str; 11] = [ +const FEATURE_VERSIONS: [&str; 12] = [ "llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8-0", "llvm9-0", "llvm10-0", "llvm11-0", "llvm12-0", "llvm13-0", - "llvm14-0", + "llvm14-0", "llvm15-0", ]; /// Gets the index of the feature version that represents `latest` diff --git a/src/debug_info.rs b/src/debug_info.rs index a47c53db405..9fc1461bc36 100644 --- a/src/debug_info.rs +++ b/src/debug_info.rs @@ -185,14 +185,16 @@ impl<'ctx> DebugInfoBuilder<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sysroot: &str, #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sdk: &str, ) -> (Self, DICompileUnit<'ctx>) { @@ -227,14 +229,16 @@ impl<'ctx> DebugInfoBuilder<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sysroot, #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sdk, ); @@ -272,14 +276,16 @@ impl<'ctx> DebugInfoBuilder<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sysroot: &str, #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sdk: &str, ) -> DICompileUnit<'ctx> { @@ -317,7 +323,8 @@ impl<'ctx> DebugInfoBuilder<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] { LLVMDIBuilderCreateCompileUnit( diff --git a/src/module.rs b/src/module.rs index cb689a56388..261cd6b20d6 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1416,14 +1416,16 @@ impl<'ctx> Module<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sysroot: &str, #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sdk: &str, ) -> (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>) { @@ -1446,14 +1448,16 @@ impl<'ctx> Module<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sysroot, #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] sdk, ) diff --git a/src/types/enums.rs b/src/types/enums.rs index 5d08868d376..2dca319826c 100644 --- a/src/types/enums.rs +++ b/src/types/enums.rs @@ -216,7 +216,8 @@ impl<'ctx> AnyTypeEnum<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)), LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"), @@ -230,12 +231,13 @@ impl<'ctx> AnyTypeEnum<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)), LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Metadata type is not supported as AnyType."), LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"), - #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0"))] + #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] LLVMTypeKind::LLVMX86_AMXTypeKind => panic!("FIXME: Unsupported type: AMX"), LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"), } @@ -383,7 +385,8 @@ impl<'ctx> BasicTypeEnum<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)), LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)), @@ -395,14 +398,15 @@ impl<'ctx> BasicTypeEnum<'ctx> { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)), LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"), // see https://llvm.org/docs/LangRef.html#x86-mmx-type LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"), // see https://llvm.org/docs/LangRef.html#x86-amx-type - #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0"))] + #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] LLVMTypeKind::LLVMX86_AMXTypeKind => unreachable!("Unsupported basic type: AMX"), LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"), LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"), diff --git a/src/values/metadata_value.rs b/src/values/metadata_value.rs index cdb8734fed6..b645fe22dbb 100644 --- a/src/values/metadata_value.rs +++ b/src/values/metadata_value.rs @@ -32,7 +32,7 @@ pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 26; pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 28; #[cfg(any(feature = "llvm10-0", feature = "llvm11-0"))] pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 30; -#[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0"))] +#[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 31; #[derive(PartialEq, Eq, Clone, Copy, Hash)] From 9dacd28268a5518faccbba6fa2bf757a67313f94 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 9 Jun 2022 17:54:37 +0200 Subject: [PATCH 03/34] Add the zkSync VM local changes --- .gitignore | 4 ++ Cargo.toml | 10 ++-- src/builder.rs | 35 +++++++----- src/lib.rs | 27 +++++---- src/module.rs | 84 +++++++++++++++++++++++++--- src/targets.rs | 40 +++++++++++++ src/types/array_type.rs | 2 +- src/types/float_type.rs | 2 +- src/types/fn_type.rs | 2 +- src/types/int_type.rs | 2 +- src/types/ptr_type.rs | 30 +++++----- src/types/struct_type.rs | 2 +- src/types/traits.rs | 2 +- src/types/vec_type.rs | 2 +- src/values/basic_value_use.rs | 6 +- src/values/instruction_value.rs | 10 ++-- tests/all/test_builder.rs | 28 +++++----- tests/all/test_context.rs | 2 +- tests/all/test_debug_info.rs | 2 +- tests/all/test_execution_engine.rs | 4 +- tests/all/test_instruction_values.rs | 14 ++--- tests/all/test_targets.rs | 2 +- tests/all/test_types.rs | 44 +++++++-------- tests/all/test_values.rs | 16 +++--- 24 files changed, 248 insertions(+), 124 deletions(-) diff --git a/.gitignore b/.gitignore index 2bb07bc394c..8ff45adee2b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +# IDE project data +/.idea/ +/.vscode/ diff --git a/Cargo.toml b/Cargo.toml index a459a52906d..d416ee3635a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ target-bpf = [] target-lanai = [] target-webassembly = [] target-riscv = [] +target-syncvm = [] target-all = [ "target-x86", "target-arm", @@ -78,7 +79,8 @@ target-all = [ "target-bpf", "target-lanai", "target-webassembly", - "target-riscv" + "target-riscv", + "target-syncvm", ] experimental = ["static-alloc"] nightly = ["inkwell_internals/nightly"] @@ -96,10 +98,10 @@ 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-120 = { package = "llvm-sys", version = "120.2.2", optional = true } +llvm-sys-130 = { package = "llvm-sys", version = "130.0.3", 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-150 = { git = "ssh://git@github.com/matter-labs-forks/llvm-sys.rs", package = "llvm-sys", branch = "llvm-15.0", optional = true } once_cell = "1.4.1" parking_lot = "0.12" static-alloc = { version = "0.2", optional = true } diff --git a/src/builder.rs b/src/builder.rs index 9b132af9a23..9f66eebe57f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -38,11 +38,11 @@ use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; use crate::support::to_c_str; -use crate::types::{AsTypeRef, BasicType, FloatMathType, IntMathType, PointerMathType, PointerType}; +use crate::types::{BasicType, AsTypeRef, PointerType, AnyType, IntMathType, PointerMathType, FloatMathType}; use crate::values::{ AggregateValue, AggregateValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, InstructionValue, IntMathValue, - IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, + IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, AnyValue, AnyValueEnum, }; #[cfg(feature = "internal-getters")] use crate::LLVMReference; @@ -762,10 +762,10 @@ impl<'ctx> Builder<'ctx> { /// let module = context.create_module("struct_gep"); /// let void_type = context.void_type(); /// let i32_ty = context.i32_type(); - /// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Generic); + /// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Zero); /// let field_types = &[i32_ty.into(), i32_ty.into()]; /// let struct_ty = context.struct_type(field_types, false); - /// let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::Generic); + /// let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::Zero); /// 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); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -852,7 +852,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let i32_type = context.i32_type(); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); /// 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); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -945,7 +945,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let i32_type = context.i32_type(); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); /// let i32_seven = i32_type.const_int(7, false); /// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false); /// let fn_value = module.add_function("ret", fn_type, None); @@ -975,7 +975,7 @@ impl<'ctx> Builder<'ctx> { /// let module = context.create_module("ret"); /// let builder = context.create_builder(); /// let i32_type = context.i32_type(); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); /// let fn_type = i32_type.fn_type(&[i32_ptr_type.into()], false); /// let fn_value = module.add_function("ret", fn_type, None); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -1333,15 +1333,24 @@ impl<'ctx> Builder<'ctx> { /// /// assert!(module.verify().is_ok()); /// ``` - pub fn build_bitcast(&self, val: V, ty: T, name: &str) -> BasicValueEnum<'ctx> + pub fn build_bitcast(&self, val: V, ty: T, name: &str) -> AnyValueEnum<'ctx> where - T: BasicType<'ctx>, - V: BasicValue<'ctx>, + T: AnyType<'ctx>, + V: AnyValue<'ctx>, { let c_string = to_c_str(name); let value = unsafe { LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr()) }; - unsafe { BasicValueEnum::new(value) } + let value = unsafe { + LLVMBuildBitCast( + self.builder, + val.as_value_ref(), + ty.as_type_ref(), + c_string.as_ptr(), + ) + }; + + unsafe { AnyValueEnum::new(value) } } pub fn build_int_s_extend_or_bit_cast>( @@ -2491,7 +2500,7 @@ 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); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false); /// let fn_value = module.add_function("rmw", fn_type, None); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -2544,7 +2553,7 @@ impl<'ctx> Builder<'ctx> { /// let module = context.create_module("cmpxchg"); /// let void_type = context.void_type(); /// let i32_type = context.i32_type(); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false); /// let fn_value = module.add_function("", fn_type, None); /// let i32_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value(); diff --git a/src/lib.rs b/src/lib.rs index 764d7789722..1127e80c2d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,17 +107,15 @@ macro_rules! assert_unique_used_features { assert_unique_used_features! {"llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8-0", "llvm9-0", "llvm10-0", "llvm11-0", "llvm12-0", "llvm13-0", "llvm14-0", "llvm15-0"} -/// Defines the address space in which a global will be inserted. -/// -/// # Remarks -/// See also: https://llvm.org/doxygen/NVPTXBaseInfo_8h_source.html +/// Defines the abstract LLVM address space. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum AddressSpace { - Generic = 0, - Global = 1, - Shared = 3, - Const = 4, - Local = 5, + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, } impl TryFrom for AddressSpace { @@ -125,11 +123,12 @@ impl TryFrom for AddressSpace { fn try_from(val: u32) -> Result { match val { - 0 => Ok(AddressSpace::Generic), - 1 => Ok(AddressSpace::Global), - 3 => Ok(AddressSpace::Shared), - 4 => Ok(AddressSpace::Const), - 5 => Ok(AddressSpace::Local), + 0 => Ok(AddressSpace::Zero), + 1 => Ok(AddressSpace::One), + 2 => Ok(AddressSpace::Two), + 3 => Ok(AddressSpace::Three), + 4 => Ok(AddressSpace::Four), + 5 => Ok(AddressSpace::Five), _ => Err(()), } } diff --git a/src/module.rs b/src/module.rs index 261cd6b20d6..4158a597cc1 100644 --- a/src/module.rs +++ b/src/module.rs @@ -22,7 +22,8 @@ use llvm_sys::error::LLVMGetErrorMessage; use llvm_sys::execution_engine::{ LLVMCreateExecutionEngineForModule, LLVMCreateInterpreterForModule, LLVMCreateJITCompilerForModule, }; -use llvm_sys::prelude::{LLVMModuleRef, LLVMValueRef}; +use llvm_sys::ir_reader::LLVMParseIRInContext; +use llvm_sys::prelude::{LLVMModuleRef, LLVMTypeRef, LLVMValueRef}; #[llvm_versions(13.0..=latest)] use llvm_sys::transforms::pass_builder::LLVMRunPasses; use llvm_sys::LLVMLinkage; @@ -619,7 +620,7 @@ impl<'ctx> Module<'ctx> { /// let context = Context::create(); /// let module = context.create_module("mod"); /// let i8_type = context.i8_type(); - /// let global = module.add_global(i8_type, Some(AddressSpace::Const), "my_global"); + /// let global = module.add_global(i8_type, Some(AddressSpace::Four), "my_global"); /// /// assert_eq!(module.get_first_global().unwrap(), global); /// assert_eq!(module.get_last_global().unwrap(), global); @@ -1033,7 +1034,7 @@ impl<'ctx> Module<'ctx> { /// /// assert!(module.get_first_global().is_none()); /// - /// let global = module.add_global(i8_type, Some(AddressSpace::Const), "my_global"); + /// let global = module.add_global(i8_type, Some(AddressSpace::Four), "my_global"); /// /// assert_eq!(module.get_first_global().unwrap(), global); /// ``` @@ -1061,7 +1062,7 @@ impl<'ctx> Module<'ctx> { /// /// assert!(module.get_last_global().is_none()); /// - /// let global = module.add_global(i8_type, Some(AddressSpace::Const), "my_global"); + /// let global = module.add_global(i8_type, Some(AddressSpace::Four), "my_global"); /// /// assert_eq!(module.get_last_global().unwrap(), global); /// ``` @@ -1089,7 +1090,7 @@ impl<'ctx> Module<'ctx> { /// /// assert!(module.get_global("my_global").is_none()); /// - /// let global = module.add_global(i8_type, Some(AddressSpace::Const), "my_global"); + /// let global = module.add_global(i8_type, Some(AddressSpace::Four), "my_global"); /// /// assert_eq!(module.get_global("my_global").unwrap(), global); /// ``` @@ -1104,7 +1105,76 @@ impl<'ctx> Module<'ctx> { unsafe { Some(GlobalValue::new(value)) } } - /// Creates a new `Module` from a `MemoryBuffer`. + /// Creates a new `Module` from a `MemoryBuffer` with IR. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::module::Module; + /// use inkwell::memory_buffer::MemoryBuffer; + /// use std::path::Path; + /// + /// let path = Path::new("foo/bar.ll"); + /// let context = Context::create(); + /// let buffer = MemoryBuffer::create_from_file(&path).unwrap(); + /// let module = Module::parse_ir_from_buffer(&buffer, &context); + /// + /// assert_eq!(*module.unwrap().get_context(), context); + /// + /// ``` + pub fn parse_ir_from_buffer( + buffer: &MemoryBuffer, + context: &'ctx Context, + ) -> Result { + let mut module = MaybeUninit::uninit(); + let mut err_string = MaybeUninit::uninit(); + + let success = unsafe { + LLVMParseIRInContext( + context.context, + buffer.memory_buffer, + module.as_mut_ptr(), + err_string.as_mut_ptr(), + ) + }; + + if success != 0 { + let err_string = unsafe { err_string.assume_init() }; + return Err(unsafe { LLVMString::new(err_string) }); + } + + let module = unsafe { module.assume_init() }; + + Ok(unsafe { Module::new(module) }) + } + + /// A convenience function for creating a `Module` from an IR file for a given context. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::module::Module; + /// use std::path::Path; + /// + /// let path = Path::new("foo/bar.ll"); + /// let context = Context::create(); + /// let module = Module::parse_ir_from_path(&path, &context); + /// + /// assert_eq!(*module.unwrap().get_context(), context); + /// + /// ``` + pub fn parse_ir_from_path>( + path: P, + context: &'ctx Context, + ) -> Result { + let buffer = MemoryBuffer::create_from_file(path.as_ref())?; + + Self::parse_ir_from_buffer(&buffer, &context) + } + + /// Creates a new `Module` from a `MemoryBuffer` with bitcode. /// /// # Example /// @@ -1148,7 +1218,7 @@ impl<'ctx> Module<'ctx> { unsafe { Ok(Module::new(module.assume_init())) } } - /// A convenience function for creating a `Module` from a file for a given context. + /// A convenience function for creating a `Module` from a bitcode file for a given context. /// /// # Example /// diff --git a/src/targets.rs b/src/targets.rs index 75fe04edf0d..102f1ceee99 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -752,6 +752,46 @@ impl Target { } } + #[cfg(feature = "target-syncvm")] + #[llvm_versions(11.0..=latest)] + pub fn initialize_syncvm(config: &InitializationConfig) { + use llvm_sys::target::{ + LLVMInitializeSyncVMAsmParser, LLVMInitializeSyncVMAsmPrinter, + LLVMInitializeSyncVMDisassembler, LLVMInitializeSyncVMTarget, + LLVMInitializeSyncVMTargetInfo, LLVMInitializeSyncVMTargetMC, + }; + + if config.base { + let _guard = TARGET_LOCK.write(); + unsafe { LLVMInitializeSyncVMTarget() }; + } + + if config.info { + let _guard = TARGET_LOCK.write(); + unsafe { LLVMInitializeSyncVMTargetInfo() }; + } + + if config.asm_printer { + let _guard = TARGET_LOCK.write(); + unsafe { LLVMInitializeSyncVMAsmPrinter() }; + } + + if config.asm_parser { + let _guard = TARGET_LOCK.write(); + unsafe { LLVMInitializeSyncVMAsmParser() }; + } + + if config.disassembler { + let _guard = TARGET_LOCK.write(); + unsafe { LLVMInitializeSyncVMDisassembler() }; + } + + if config.machine_code { + let _guard = TARGET_LOCK.write(); + unsafe { LLVMInitializeSyncVMTargetMC() }; + } + } + pub fn initialize_native(config: &InitializationConfig) -> Result<(), String> { use llvm_sys::target::{ LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeDisassembler, diff --git a/src/types/array_type.rs b/src/types/array_type.rs index 703b0d3b559..6a802573fc8 100644 --- a/src/types/array_type.rs +++ b/src/types/array_type.rs @@ -70,7 +70,7 @@ impl<'ctx> ArrayType<'ctx> { /// let context = Context::create(); /// let i8_type = context.i8_type(); /// let i8_array_type = i8_type.array_type(3); - /// let i8_array_ptr_type = i8_array_type.ptr_type(AddressSpace::Generic); + /// let i8_array_ptr_type = i8_array_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(i8_array_ptr_type.get_element_type().into_array_type(), i8_array_type); /// ``` diff --git a/src/types/float_type.rs b/src/types/float_type.rs index 20638affd49..be3f47737aa 100644 --- a/src/types/float_type.rs +++ b/src/types/float_type.rs @@ -209,7 +209,7 @@ impl<'ctx> FloatType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type); /// ``` diff --git a/src/types/fn_type.rs b/src/types/fn_type.rs index 194c9f86fa3..7dfc2bfd029 100644 --- a/src/types/fn_type.rs +++ b/src/types/fn_type.rs @@ -39,7 +39,7 @@ impl<'ctx> FunctionType<'ctx> { /// let context = Context::create(); /// let f32_type = context.f32_type(); /// let fn_type = f32_type.fn_type(&[], false); - /// let fn_ptr_type = fn_type.ptr_type(AddressSpace::Global); + /// let fn_ptr_type = fn_type.ptr_type(AddressSpace::One); /// /// assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type); /// ``` diff --git a/src/types/int_type.rs b/src/types/int_type.rs index 4350afe3def..2231dcf3ef1 100644 --- a/src/types/int_type.rs +++ b/src/types/int_type.rs @@ -304,7 +304,7 @@ impl<'ctx> IntType<'ctx> { /// /// let context = Context::create(); /// let i8_type = context.i8_type(); - /// let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = i8_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(i8_ptr_type.get_element_type().into_int_type(), i8_type); /// ``` diff --git a/src/types/ptr_type.rs b/src/types/ptr_type.rs index 28283ed472e..495e9de55a7 100644 --- a/src/types/ptr_type.rs +++ b/src/types/ptr_type.rs @@ -37,7 +37,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_type_size = f32_ptr_type.size_of(); /// ``` pub fn size_of(self) -> IntValue<'ctx> { @@ -54,7 +54,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_type_alignment = f32_ptr_type.get_alignment(); /// ``` pub fn get_alignment(self) -> IntValue<'ctx> { @@ -71,8 +71,8 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); - /// let f32_ptr_ptr_type = f32_ptr_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); + /// let f32_ptr_ptr_type = f32_ptr_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(f32_ptr_ptr_type.get_element_type().into_pointer_type(), f32_ptr_type); /// ``` @@ -90,7 +90,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(f32_ptr_type.get_context(), context); /// ``` @@ -109,7 +109,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = f32_ptr_type.fn_type(&[], false); /// ``` pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> { @@ -126,7 +126,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_array_type = f32_ptr_type.array_type(3); /// /// assert_eq!(f32_ptr_array_type.len(), 3); @@ -146,9 +146,9 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// - /// assert_eq!(f32_ptr_type.get_address_space(), AddressSpace::Generic); + /// assert_eq!(f32_ptr_type.get_address_space(), AddressSpace::Zero); /// ``` pub fn get_address_space(self) -> AddressSpace { let addr_space = unsafe { LLVMGetPointerAddressSpace(self.as_type_ref()) }; @@ -172,7 +172,7 @@ impl<'ctx> PointerType<'ctx> { /// // Local Context /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_null = f32_ptr_type.const_null(); /// /// assert!(f32_ptr_null.is_null()); @@ -194,7 +194,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_zero = f32_ptr_type.const_zero(); /// ``` pub fn const_zero(self) -> PointerValue<'ctx> { @@ -210,7 +210,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_undef = f32_ptr_type.get_undef(); /// /// assert!(f32_ptr_undef.is_undef()); @@ -229,7 +229,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let f32_ptr_vec_type = f32_ptr_type.vec_type(3); /// /// assert_eq!(f32_ptr_vec_type.get_size(), 3); @@ -250,7 +250,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type); /// ``` @@ -267,7 +267,7 @@ impl<'ctx> PointerType<'ctx> { /// /// let context = Context::create(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// 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/struct_type.rs b/src/types/struct_type.rs index aaf2a8881d6..ee320c4227b 100644 --- a/src/types/struct_type.rs +++ b/src/types/struct_type.rs @@ -186,7 +186,7 @@ impl<'ctx> StructType<'ctx> { /// let context = Context::create(); /// let f32_type = context.f32_type(); /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false); - /// let struct_ptr_type = struct_type.ptr_type(AddressSpace::Generic); + /// let struct_ptr_type = struct_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(struct_ptr_type.get_element_type().into_struct_type(), struct_type); /// ``` diff --git a/src/types/traits.rs b/src/types/traits.rs index 8fabcf4066f..2692cbf6494 100644 --- a/src/types/traits.rs +++ b/src/types/traits.rs @@ -126,7 +126,7 @@ pub trait BasicType<'ctx>: AnyType<'ctx> { /// let context = Context::create(); /// let int = context.i32_type(); /// let int_basic_type = int.as_basic_type_enum(); - /// let addr_space = AddressSpace::Generic; + /// let addr_space = AddressSpace::Zero; /// assert_eq!(int_basic_type.ptr_type(addr_space), int.ptr_type(addr_space)); /// ``` fn ptr_type(&self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/vec_type.rs b/src/types/vec_type.rs index 179f304dd0e..2f8af96e568 100644 --- a/src/types/vec_type.rs +++ b/src/types/vec_type.rs @@ -175,7 +175,7 @@ impl<'ctx> VectorType<'ctx> { /// let context = Context::create(); /// let f32_type = context.f32_type(); /// let f32_vec_type = f32_type.vec_type(3); - /// let f32_vec_ptr_type = f32_vec_type.ptr_type(AddressSpace::Generic); + /// let f32_vec_ptr_type = f32_vec_type.ptr_type(AddressSpace::Zero); /// /// assert_eq!(f32_vec_ptr_type.get_element_type().into_vector_type(), f32_vec_type); /// ``` diff --git a/src/values/basic_value_use.rs b/src/values/basic_value_use.rs index 4ca8e24e71a..0767a54c3c1 100644 --- a/src/values/basic_value_use.rs +++ b/src/values/basic_value_use.rs @@ -35,7 +35,7 @@ impl<'ctx> BasicValueUse<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); @@ -96,7 +96,7 @@ impl<'ctx> BasicValueUse<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); @@ -132,7 +132,7 @@ impl<'ctx> BasicValueUse<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); diff --git a/src/values/instruction_value.rs b/src/values/instruction_value.rs index 3e6270a3546..2e88c37b6b5 100644 --- a/src/values/instruction_value.rs +++ b/src/values/instruction_value.rs @@ -345,7 +345,7 @@ impl<'ctx> InstructionValue<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); @@ -405,7 +405,7 @@ impl<'ctx> InstructionValue<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); @@ -488,7 +488,7 @@ impl<'ctx> InstructionValue<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); @@ -531,7 +531,7 @@ impl<'ctx> InstructionValue<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); @@ -577,7 +577,7 @@ impl<'ctx> InstructionValue<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let f32_type = context.f32_type(); - /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); /// /// let function = module.add_function("take_f32_ptr", fn_type, None); diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs index 060319549e8..13c8971a05d 100644 --- a/tests/all/test_builder.rs +++ b/tests/all/test_builder.rs @@ -301,7 +301,7 @@ fn test_null_checked_ptr_ops() { // } let i8_type = context.i8_type(); - let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic); + let i8_ptr_type = i8_type.ptr_type(AddressSpace::Zero); let i64_type = context.i64_type(); let fn_type = i8_type.fn_type(&[i8_ptr_type.into()], false); let neg_one = i8_type.const_all_ones(); @@ -841,7 +841,7 @@ 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); - let i8_ptr_vec_type = context.i8_type().ptr_type(AddressSpace::Generic).vec_type(4); + let i8_ptr_vec_type = context.i8_type().ptr_type(AddressSpace::Zero).vec_type(4); let bool_vec_type = context.bool_type().vec_type(4); // Here we're building a function that takes a <4 x i32>, converts it to a <4 x i8*> and returns a @@ -990,7 +990,7 @@ fn run_memcpy_on<'ctx>( let i32_type = context.i32_type(); let i64_type = context.i64_type(); let array_len = 4; - let fn_type = i32_type.ptr_type(AddressSpace::Generic).fn_type(&[], false); + let fn_type = i32_type.ptr_type(AddressSpace::Zero).fn_type(&[], false); let fn_value = module.add_function("test_fn", fn_type, None); let builder = context.create_builder(); let entry = context.append_basic_block(fn_value, "entry"); @@ -1060,7 +1060,7 @@ fn run_memmove_on<'ctx>( let i32_type = context.i32_type(); let i64_type = context.i64_type(); let array_len = 4; - let fn_type = i32_type.ptr_type(AddressSpace::Generic).fn_type(&[], false); + let fn_type = i32_type.ptr_type(AddressSpace::Zero).fn_type(&[], false); let fn_value = module.add_function("test_fn", fn_type, None); let builder = context.create_builder(); let entry = context.append_basic_block(fn_value, "entry"); @@ -1194,8 +1194,8 @@ fn test_bitcast() { let i32_type = context.i32_type(); let f64_type = context.f64_type(); let i64_type = context.i64_type(); - let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); - let i64_ptr_type = i64_type.ptr_type(AddressSpace::Generic); + let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); + let i64_ptr_type = i64_type.ptr_type(AddressSpace::Zero); let i32_vec_type = i32_type.vec_type(2); let arg_types = [ i32_type.into(), @@ -1251,22 +1251,22 @@ fn test_atomicrmw() { let i31_type = context.custom_width_int_type(31); let i4_type = context.custom_width_int_type(4); - let ptr_value = i32_type.ptr_type(AddressSpace::Generic).get_undef(); + let ptr_value = i32_type.ptr_type(AddressSpace::Zero).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()); - let ptr_value = i64_type.ptr_type(AddressSpace::Generic).get_undef(); + let ptr_value = i64_type.ptr_type(AddressSpace::Zero).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_err()); - let ptr_value = i31_type.ptr_type(AddressSpace::Generic).get_undef(); + let ptr_value = i31_type.ptr_type(AddressSpace::Zero).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()); - let ptr_value = i4_type.ptr_type(AddressSpace::Generic).get_undef(); + let ptr_value = i4_type.ptr_type(AddressSpace::Zero).get_undef(); let zero_value = i4_type.const_zero(); let result = builder.build_atomicrmw(AtomicRMWBinOp::Add, ptr_value, zero_value, AtomicOrdering::Unordered); assert!(result.is_err()); @@ -1286,8 +1286,8 @@ fn test_cmpxchg() { let i32_type = context.i32_type(); let i64_type = context.i64_type(); - let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); - let i32_ptr_ptr_type = i32_ptr_type.ptr_type(AddressSpace::Generic); + let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); + let i32_ptr_ptr_type = i32_ptr_type.ptr_type(AddressSpace::Zero); let ptr_value = i32_ptr_type.get_undef(); let zero_value = i32_type.const_zero(); @@ -1429,10 +1429,10 @@ fn test_safe_struct_gep() { let module = context.create_module("struct_gep"); let void_type = context.void_type(); let i32_ty = context.i32_type(); - let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Generic); + let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Zero); let field_types = &[i32_ty.into(), i32_ty.into()]; let struct_ty = context.struct_type(field_types, false); - let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::Generic); + let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::Zero); 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); let entry = context.append_basic_block(fn_value, "entry"); diff --git a/tests/all/test_context.rs b/tests/all/test_context.rs index 5e19ea29590..813b9d35dc0 100644 --- a/tests/all/test_context.rs +++ b/tests/all/test_context.rs @@ -53,7 +53,7 @@ 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); - let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); let f32_array_type = f32_type.array_type(2); let fn_type = f32_type.fn_type(&[], false); let struct_type = context.struct_type(&[i8_type.into(), f32_type.into()], false); diff --git a/tests/all/test_debug_info.rs b/tests/all/test_debug_info.rs index 1e27d39660b..d6d1ae8e653 100644 --- a/tests/all/test_debug_info.rs +++ b/tests/all/test_debug_info.rs @@ -388,7 +388,7 @@ fn test_global_expressions() { ); let di_type = dibuilder.create_basic_type("type_name", 0_u64, 0x00, DIFlags::ZERO); - let gv = module.add_global(context.i64_type(), Some(inkwell::AddressSpace::Global), "gv"); + let gv = module.add_global(context.i64_type(), Some(inkwell::AddressSpace::One), "gv"); let const_v = dibuilder.create_constant_expression(10); diff --git a/tests/all/test_execution_engine.rs b/tests/all/test_execution_engine.rs index c2d1afe01fa..1f87f0ff594 100644 --- a/tests/all/test_execution_engine.rs +++ b/tests/all/test_execution_engine.rs @@ -55,8 +55,8 @@ fn test_jit_execution_engine() { let builder = context.create_builder(); let i8_type = context.i8_type(); let i32_type = context.i32_type(); - let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic); - let i8_ptr_ptr_type = i8_ptr_type.ptr_type(AddressSpace::Generic); + let i8_ptr_type = i8_type.ptr_type(AddressSpace::Zero); + let i8_ptr_ptr_type = i8_ptr_type.ptr_type(AddressSpace::Zero); let one_i32 = i32_type.const_int(1, false); let three_i32 = i32_type.const_int(3, false); let fourtytwo_i32 = i32_type.const_int(42, false); diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index 5edbc1fad60..2a33d4dd126 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -10,7 +10,7 @@ fn test_operands() { let builder = context.create_builder(); let void_type = context.void_type(); let f32_type = context.f32_type(); - let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false); let function = module.add_function("take_f32_ptr", fn_type, None); @@ -207,7 +207,7 @@ fn test_instructions() { let void_type = context.void_type(); let i64_type = context.i64_type(); let f32_type = context.f32_type(); - let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false); let function = module.add_function("free_f32", fn_type, None); @@ -281,7 +281,7 @@ fn test_volatile_atomicrmw_cmpxchg() { let void_type = context.void_type(); let i32_type = context.i32_type(); - let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic); + let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); let fn_type = void_type.fn_type(&[i32_ptr_type.into(), i32_type.into()], false); let function = module.add_function("mem_inst", fn_type, None); @@ -335,7 +335,7 @@ fn test_mem_instructions() { let void_type = context.void_type(); let f32_type = context.f32_type(); - let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false); let function = module.add_function("mem_inst", fn_type, None); @@ -399,7 +399,7 @@ fn test_mem_instructions() { let void_type = context.void_type(); let f32_type = context.f32_type(); - let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false); let function = module.add_function("mem_inst", fn_type, None); @@ -462,7 +462,7 @@ fn test_atomic_ordering_mem_instructions() { let void_type = context.void_type(); let f32_type = context.f32_type(); - let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic); + let f32_ptr_type = f32_type.ptr_type(AddressSpace::Zero); let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false); let function = module.add_function("mem_inst", fn_type, None); @@ -521,7 +521,7 @@ fn test_metadata_kinds() { let i8_type = context.i8_type(); let f32_type = context.f32_type(); - let ptr_type = i8_type.ptr_type(AddressSpace::Generic); + let ptr_type = i8_type.ptr_type(AddressSpace::Zero); let struct_type = context.struct_type(&[i8_type.into(), f32_type.into()], false); let vector_type = i8_type.vec_type(2); diff --git a/tests/all/test_targets.rs b/tests/all/test_targets.rs index 1efd9c0f63d..5f674718d60 100644 --- a/tests/all/test_targets.rs +++ b/tests/all/test_targets.rs @@ -302,7 +302,7 @@ fn test_ptr_sized_int() { let module = context.create_module("sum"); let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap(); let target_data = execution_engine.get_target_data(); - let address_space = AddressSpace::Global; + let address_space = AddressSpace::One; let int_type = context.ptr_sized_int_type(&target_data, None); assert_eq!(int_type.get_bit_width(), target_data.get_pointer_byte_size(None) * 8); diff --git a/tests/all/test_types.rs b/tests/all/test_types.rs index b39ebf46812..e0d25e3c0ce 100644 --- a/tests/all/test_types.rs +++ b/tests/all/test_types.rs @@ -165,22 +165,22 @@ fn sized_types(global_ctx: &Context) { assert!(!fn_type3.is_sized()); assert!(!fn_type4.is_sized()); - assert!(bool_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(i8_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(i16_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(i32_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(i64_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(i128_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(f16_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(f32_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(f64_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(f80_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(f128_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(ppc_f128_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(struct_type.ptr_type(AddressSpace::Generic).is_sized()); - assert!(struct_type2.ptr_type(AddressSpace::Generic).is_sized()); - assert!(struct_type3.ptr_type(AddressSpace::Generic).is_sized()); - assert!(struct_type4.ptr_type(AddressSpace::Generic).is_sized()); + assert!(bool_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(i8_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(i16_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(i32_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(i64_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(i128_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(f16_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(f32_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(f64_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(f80_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(f128_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(ppc_f128_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(struct_type.ptr_type(AddressSpace::Zero).is_sized()); + assert!(struct_type2.ptr_type(AddressSpace::Zero).is_sized()); + assert!(struct_type3.ptr_type(AddressSpace::Zero).is_sized()); + assert!(struct_type4.ptr_type(AddressSpace::Zero).is_sized()); assert!(bool_type.array_type(42).is_sized()); assert!(i8_type.array_type(42).is_sized()); @@ -215,7 +215,7 @@ fn sized_types(global_ctx: &Context) { let opaque_struct_type = global_ctx.opaque_struct_type("opaque"); assert!(!opaque_struct_type.is_sized()); - assert!(opaque_struct_type.ptr_type(AddressSpace::Generic).is_sized()); + assert!(opaque_struct_type.ptr_type(AddressSpace::Zero).is_sized()); assert!(!opaque_struct_type.array_type(0).is_sized()); } @@ -235,7 +235,7 @@ 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); - let ptr_type = f64_type.ptr_type(AddressSpace::Generic); + let ptr_type = f64_type.ptr_type(AddressSpace::Zero); let vec_type = f64_type.vec_type(42); let array_type = f64_type.array_type(42); @@ -342,15 +342,15 @@ fn test_type_copies() { fn test_ptr_type() { let context = Context::create(); let i8_type = context.i8_type(); - let ptr_type = i8_type.ptr_type(AddressSpace::Generic); + let ptr_type = i8_type.ptr_type(AddressSpace::Zero); - assert_eq!(ptr_type.get_address_space(), AddressSpace::Generic); + assert_eq!(ptr_type.get_address_space(), AddressSpace::Zero); assert_eq!(ptr_type.get_element_type().into_int_type(), i8_type); // Fn ptr: let void_type = context.void_type(); let fn_type = void_type.fn_type(&[], false); - let fn_ptr_type = fn_type.ptr_type(AddressSpace::Generic); + let fn_ptr_type = fn_type.ptr_type(AddressSpace::Zero); assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type); assert_eq!(fn_ptr_type.get_context(), context); @@ -359,7 +359,7 @@ fn test_ptr_type() { #[test] fn test_basic_type_enum() { let context = Context::create(); - let addr = AddressSpace::Generic; + let addr = AddressSpace::Zero; let int = context.i32_type(); let types: &[&dyn BasicType] = &[ // ints and floats diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index 165bc33ee07..d6796a46342 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -87,7 +87,7 @@ 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); - let ptr_val = bool_type.ptr_type(AddressSpace::Generic).const_null(); + let ptr_val = bool_type.ptr_type(AddressSpace::Zero).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]); @@ -143,7 +143,7 @@ fn test_set_get_name() { assert_eq!(ppc_f128_val.get_name().to_str(), Ok("")); let void_type = context.void_type(); - let ptr_type = bool_type.ptr_type(AddressSpace::Generic); + let ptr_type = bool_type.ptr_type(AddressSpace::Zero); let struct_type = context.struct_type(&[bool_type.into()], false); let vec_type = bool_type.vec_type(1); @@ -229,7 +229,7 @@ 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); - let ptr_val = bool_type.ptr_type(AddressSpace::Generic).const_null(); + let ptr_val = bool_type.ptr_type(AddressSpace::Zero).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]); @@ -261,7 +261,7 @@ fn test_undef() { let f32_undef = f32_type.get_undef(); let f64_undef = f64_type.get_undef(); let f128_undef = f128_type.get_undef(); - let ptr_undef = bool_type.ptr_type(AddressSpace::Generic).get_undef(); + let ptr_undef = bool_type.ptr_type(AddressSpace::Zero).get_undef(); let array_undef = array_type.get_undef(); let struct_undef = context.struct_type(&[bool_type.into()], false).get_undef(); let vec_undef = bool_type.vec_type(1).get_undef(); @@ -678,7 +678,7 @@ fn test_global_byte_array() { let my_str = "Hello, World"; let i8_type = context.i8_type(); let i8_array_type = i8_type.array_type(my_str.len() as u32); - let global_string = module.add_global(i8_array_type, Some(AddressSpace::Generic), "message"); + let global_string = module.add_global(i8_array_type, Some(AddressSpace::Zero), "message"); let mut chars = Vec::with_capacity(my_str.len()); @@ -810,7 +810,7 @@ fn test_globals() { assert!(global.get_thread_local_mode().is_none()); - let global2 = module.add_global(i8_type, Some(AddressSpace::Const), "my_global2"); + let global2 = module.add_global(i8_type, Some(AddressSpace::Four), "my_global2"); assert_eq!(global2.get_previous_global().unwrap(), global); assert_eq!(global.get_next_global().unwrap(), global2); @@ -1134,7 +1134,7 @@ fn test_non_fn_ptr_called() { let builder = context.create_builder(); let module = context.create_module("my_mod"); let i8_type = context.i8_type(); - let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic); + let i8_ptr_type = i8_type.ptr_type(AddressSpace::Zero); let fn_type = i8_type.fn_type(&[i8_ptr_type.into()], false); let fn_value = module.add_function("my_func", fn_type, None); let bb = context.append_basic_block(fn_value, "entry"); @@ -1178,7 +1178,7 @@ fn test_aggregate_returns() { let builder = context.create_builder(); let module = context.create_module("my_mod"); let i32_type = context.i32_type(); - let i32_ptr_type = i32_type.ptr_type(AddressSpace::Local); + let i32_ptr_type = i32_type.ptr_type(AddressSpace::Five); let i32_three = i32_type.const_int(3, false); let i32_seven = i32_type.const_int(7, false); let struct_type = context.struct_type(&[i32_type.into(), i32_type.into()], false); From 09c83e7348e95b834bb1f8ec5056bd3d4c0089ec Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 9 Jun 2022 21:38:37 +0200 Subject: [PATCH 04/34] Add the LLVMParseCommandLineOptions binding --- src/support/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/support/mod.rs b/src/support/mod.rs index 24121f41eab..016f9e6acec 100644 --- a/src/support/mod.rs +++ b/src/support/mod.rs @@ -5,6 +5,7 @@ use libc::c_char; use llvm_sys::core::{LLVMCreateMessage, LLVMDisposeMessage}; use llvm_sys::error_handling::LLVMEnablePrettyStackTrace; use llvm_sys::support::LLVMLoadLibraryPermanently; +use llvm_sys::support::LLVMParseCommandLineOptions; use std::borrow::Cow; use std::error::Error; @@ -123,6 +124,18 @@ pub unsafe fn shutdown_llvm() { LLVMShutdown() } +pub fn parse_command_line_options(argc: i32, argv: &[&str], overview: &str) { + let argv: Vec<*const ::libc::c_char> = argv + .iter() + .map(|arg| to_c_str(arg).as_ptr()) + .collect(); + let overview = to_c_str(overview); + + unsafe { + LLVMParseCommandLineOptions(argc, argv.as_ptr(), overview.as_ptr()); + } +} + pub fn load_library_permanently(filename: &str) -> bool { let filename = to_c_str(filename); From 30efb42e64adf6b0f43f4e51c42ce34132dd3f17 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Mon, 11 Jul 2022 20:46:32 +0200 Subject: [PATCH 05/34] Change the dependencies protocol to HTTPS --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d416ee3635a..08adf3853e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,7 @@ llvm-sys-110 = { package = "llvm-sys", version = "110.0.3", optional = true } llvm-sys-120 = { package = "llvm-sys", version = "120.2.2", optional = true } llvm-sys-130 = { package = "llvm-sys", version = "130.0.3", optional = true } llvm-sys-140 = { package = "llvm-sys", version = "140.0.2", optional = true } -llvm-sys-150 = { git = "ssh://git@github.com/matter-labs-forks/llvm-sys.rs", package = "llvm-sys", branch = "llvm-15.0", optional = true } +llvm-sys-150 = { git = "https://github.com/matter-labs-forks/llvm-sys.rs", package = "llvm-sys", branch = "llvm-15.0", optional = true } once_cell = "1.4.1" parking_lot = "0.12" static-alloc = { version = "0.2", optional = true } From 2a5b19311abca87a4fcb468af524ed3ac16b7a38 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 17 Nov 2022 15:34:48 +0100 Subject: [PATCH 06/34] Make 'inkwell' compiler with LLVM 15 1. Remove the `LLVMConst*` function family 2. Remove some optimization passes, including those for coroutines 3. Update the `AtomicRMWBinOp` enum --- src/lib.rs | 10 ++++ src/module.rs | 2 +- src/passes.rs | 113 +------------------------------------- src/values/float_value.rs | 24 +------- src/values/int_value.rs | 35 ++---------- src/values/traits.rs | 26 --------- 6 files changed, 20 insertions(+), 190 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1127e80c2d3..96d9850cc14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,6 +330,16 @@ pub enum AtomicRMWBinOp { #[llvm_versions(10.0..=latest)] #[llvm_variant(LLVMAtomicRMWBinOpFSub)] FSub, + + /// Sets memory to the float-typed-greater of the value provided and the value in memory. Returns the value that was in memory. + #[llvm_versions(15.0..=latest)] + #[llvm_variant(LLVMAtomicRMWBinOpFMax)] + FMax, + + /// Sets memory to the float-typed-lesser of the value provided and the value in memory. Returns the value that was in memory. + #[llvm_versions(15.0..=latest)] + #[llvm_variant(LLVMAtomicRMWBinOpFMin)] + FMin, } /// Defines the optimization level used to compile a `Module`. diff --git a/src/module.rs b/src/module.rs index 4158a597cc1..d61868d990a 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1132,7 +1132,7 @@ impl<'ctx> Module<'ctx> { let success = unsafe { LLVMParseIRInContext( - context.context, + context.context.0, buffer.memory_buffer, module.as_mut_ptr(), err_string.as_mut_ptr(), diff --git a/src/passes.rs b/src/passes.rs index 118b1fa1e08..a562758d840 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -12,14 +12,14 @@ use llvm_sys::prelude::{LLVMPassManagerRef, LLVMPassRegistryRef}; #[llvm_versions(10.0..=latest)] use llvm_sys::transforms::ipo::LLVMAddMergeFunctionsPass; use llvm_sys::transforms::ipo::{ - LLVMAddAlwaysInlinerPass, LLVMAddArgumentPromotionPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, + LLVMAddAlwaysInlinerPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, LLVMAddFunctionAttrsPass, LLVMAddFunctionInliningPass, LLVMAddGlobalDCEPass, LLVMAddGlobalOptimizerPass, LLVMAddIPSCCPPass, LLVMAddInternalizePass, LLVMAddPruneEHPass, LLVMAddStripDeadPrototypesPass, LLVMAddStripSymbolsPass, }; use llvm_sys::transforms::pass_manager_builder::{ LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderPopulateFunctionPassManager, - LLVMPassManagerBuilderPopulateLTOPassManager, LLVMPassManagerBuilderPopulateModulePassManager, + LLVMPassManagerBuilderPopulateModulePassManager, LLVMPassManagerBuilderRef, LLVMPassManagerBuilderSetDisableSimplifyLibCalls, LLVMPassManagerBuilderSetDisableUnitAtATime, LLVMPassManagerBuilderSetDisableUnrollLoops, LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderSetSizeLevel, @@ -31,7 +31,7 @@ use llvm_sys::transforms::scalar::{ LLVMAddDeadStoreEliminationPass, LLVMAddDemoteMemoryToRegisterPass, LLVMAddEarlyCSEPass, LLVMAddGVNPass, LLVMAddIndVarSimplifyPass, LLVMAddInstructionCombiningPass, LLVMAddJumpThreadingPass, LLVMAddLICMPass, LLVMAddLoopDeletionPass, LLVMAddLoopIdiomPass, LLVMAddLoopRerollPass, LLVMAddLoopRotatePass, LLVMAddLoopUnrollPass, - LLVMAddLoopUnswitchPass, LLVMAddLowerExpectIntrinsicPass, LLVMAddMemCpyOptPass, LLVMAddMergedLoadStoreMotionPass, + LLVMAddLowerExpectIntrinsicPass, LLVMAddMemCpyOptPass, LLVMAddMergedLoadStoreMotionPass, LLVMAddPartiallyInlineLibCallsPass, LLVMAddReassociatePass, LLVMAddSCCPPass, LLVMAddScalarReplAggregatesPass, LLVMAddScalarReplAggregatesPassSSA, LLVMAddScalarReplAggregatesPassWithThreshold, LLVMAddScalarizerPass, LLVMAddScopedNoAliasAAPass, LLVMAddSimplifyLibCallsPass, LLVMAddTailCallEliminationPass, @@ -162,37 +162,6 @@ impl PassManagerBuilder { pub fn populate_module_pass_manager(&self, pass_manager: &PassManager) { unsafe { LLVMPassManagerBuilderPopulateModulePassManager(self.pass_manager_builder, pass_manager.pass_manager) } } - - /// Populates a PassManager with the expectation of link time - /// optimization transformations. - /// - /// # Example - /// - /// ```no_run - /// use inkwell::OptimizationLevel::Aggressive; - /// use inkwell::passes::{PassManager, PassManagerBuilder}; - /// use inkwell::targets::{InitializationConfig, Target}; - /// - /// let config = InitializationConfig::default(); - /// Target::initialize_native(&config).unwrap(); - /// let pass_manager_builder = PassManagerBuilder::create(); - /// - /// pass_manager_builder.set_optimization_level(Aggressive); - /// - /// let lpm = PassManager::create(()); - /// - /// pass_manager_builder.populate_lto_pass_manager(&lpm, false, false); - /// ``` - pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) { - unsafe { - LLVMPassManagerBuilderPopulateLTOPassManager( - self.pass_manager_builder, - pass_manager.pass_manager, - internalize as i32, - run_inliner as i32, - ) - } - } } impl Drop for PassManagerBuilder { @@ -282,28 +251,6 @@ impl PassManager { unsafe { input.run_in_pass_manager(self) } } - /// This pass promotes "by reference" arguments to be "by value" arguments. - /// In practice, this means looking for internal functions that have pointer - /// arguments. If it can prove, through the use of alias analysis, that an - /// argument is only loaded, then it can pass the value into the function - /// instead of the address of the value. This can cause recursive simplification - /// of code and lead to the elimination of allocas (especially in C++ template - /// code like the STL). - /// - /// This pass also handles aggregate arguments that are passed into a function, - /// scalarizing them if the elements of the aggregate are only loaded. Note that - /// it refuses to scalarize aggregates which would require passing in more than - /// three operands to the function, because passing thousands of operands for a - /// large array or structure is unprofitable! - /// - /// Note that this transformation could also be done for arguments that are - /// only stored to (returning the value instead), but does not currently. - /// This case would be best handled when and if LLVM starts supporting multiple - /// return values from functions. - pub fn add_argument_promotion_pass(&self) { - unsafe { LLVMAddArgumentPromotionPass(self.pass_manager) } - } - /// Merges duplicate global constants together into a single constant that is /// shared. This is useful because some passes (i.e., TraceValues) insert a lot /// of string constants into the program, regardless of whether or not an existing @@ -699,32 +646,6 @@ impl PassManager { unsafe { LLVMAddLoopUnrollPass(self.pass_manager) } } - /// This pass transforms loops that contain branches on - /// loop-invariant conditions to have multiple loops. - /// For example, it turns the left into the right code: - /// - /// ```c - /// for (...) if (lic) - /// A for (...) - /// if (lic) A; B; C - /// B else - /// C for (...) - /// A; C - /// ``` - /// - /// This can increase the size of the code exponentially - /// (doubling it every time a loop is unswitched) so we - /// only unswitch if the resultant code will be smaller - /// than a threshold. - /// - /// This pass expects [LICM](https://llvm.org/docs/Passes.html#passes-licm) - /// to be run before it to hoist invariant conditions - /// out of the loop, to make the unswitching opportunity - /// obvious. - pub fn add_loop_unswitch_pass(&self) { - unsafe { LLVMAddLoopUnswitchPass(self.pass_manager) } - } - /// This pass performs various transformations related /// to eliminating memcpy calls, or transforming sets /// of stores into memsets. @@ -1007,34 +928,6 @@ impl PassManager { unsafe { LLVMAddLoopUnrollAndJamPass(self.pass_manager) } } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_early_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroEarlyPass; - - unsafe { LLVMAddCoroEarlyPass(self.pass_manager) } - } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_split_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroSplitPass; - - unsafe { LLVMAddCoroSplitPass(self.pass_manager) } - } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_elide_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroElidePass; - - unsafe { LLVMAddCoroElidePass(self.pass_manager) } - } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_cleanup_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroCleanupPass; - - unsafe { LLVMAddCoroCleanupPass(self.pass_manager) } - } } impl Drop for PassManager { diff --git a/src/values/float_value.rs b/src/values/float_value.rs index c3ba6c85dc1..b494dd5bef2 100644 --- a/src/values/float_value.rs +++ b/src/values/float_value.rs @@ -1,6 +1,6 @@ use llvm_sys::core::{ - LLVMConstFAdd, LLVMConstFCmp, LLVMConstFDiv, LLVMConstFMul, LLVMConstFNeg, LLVMConstFPCast, LLVMConstFPExt, - LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc, LLVMConstFRem, LLVMConstFSub, LLVMConstRealGetDouble, + LLVMConstFCmp, LLVMConstFNeg, LLVMConstFPCast, LLVMConstFPExt, + LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc, LLVMConstRealGetDouble, }; use llvm_sys::prelude::LLVMValueRef; @@ -64,26 +64,6 @@ impl<'ctx> FloatValue<'ctx> { unsafe { FloatValue::new(LLVMConstFNeg(self.as_value_ref())) } } - pub fn const_add(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFAdd(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_sub(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFSub(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_mul(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFMul(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_div(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_remainder(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFRem(self.as_value_ref(), rhs.as_value_ref())) } - } - pub fn const_cast(self, float_type: FloatType<'ctx>) -> Self { unsafe { FloatValue::new(LLVMConstFPCast(self.as_value_ref(), float_type.as_type_ref())) } } diff --git a/src/values/int_value.rs b/src/values/int_value.rs index 5e4846569a0..ebb992afa40 100644 --- a/src/values/int_value.rs +++ b/src/values/int_value.rs @@ -1,12 +1,10 @@ -#[llvm_versions(4.0..=latest)] -use llvm_sys::core::LLVMConstExactUDiv; use llvm_sys::core::{ - LLVMConstAShr, LLVMConstAdd, LLVMConstAnd, LLVMConstBitCast, LLVMConstExactSDiv, LLVMConstICmp, LLVMConstIntCast, + LLVMConstAShr, LLVMConstAdd, LLVMConstAnd, LLVMConstBitCast, LLVMConstICmp, LLVMConstIntCast, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr, LLVMConstLShr, LLVMConstMul, LLVMConstNSWAdd, LLVMConstNSWMul, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWMul, - LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSDiv, LLVMConstSExt, - LLVMConstSExtOrBitCast, LLVMConstSIToFP, LLVMConstSRem, LLVMConstSelect, LLVMConstShl, LLVMConstSub, - LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstUDiv, LLVMConstUIToFP, LLVMConstURem, LLVMConstXor, + LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSExt, + LLVMConstSExtOrBitCast, LLVMConstSIToFP, LLVMConstSelect, LLVMConstShl, LLVMConstSub, + LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstUIToFP, LLVMConstXor, LLVMConstZExt, LLVMConstZExtOrBitCast, LLVMIsAConstantInt, }; use llvm_sys::prelude::LLVMValueRef; @@ -120,31 +118,6 @@ impl<'ctx> IntValue<'ctx> { unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) } } - pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - #[llvm_versions(4.0..=latest)] - pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstSRem(self.as_value_ref(), rhs.as_value_ref())) } - } - pub fn const_and(self, rhs: IntValue<'ctx>) -> Self { unsafe { IntValue::new(LLVMConstAnd(self.as_value_ref(), rhs.as_value_ref())) } } diff --git a/src/values/traits.rs b/src/values/traits.rs index 366f74e9f18..957671fa673 100644 --- a/src/values/traits.rs +++ b/src/values/traits.rs @@ -1,4 +1,3 @@ -use llvm_sys::core::{LLVMConstExtractValue, LLVMConstInsertValue}; use llvm_sys::prelude::LLVMValueRef; use std::fmt::Debug; @@ -51,31 +50,6 @@ pub trait AggregateValue<'ctx>: BasicValue<'ctx> { fn as_aggregate_value_enum(&self) -> AggregateValueEnum<'ctx> { unsafe { AggregateValueEnum::new(self.as_value_ref()) } } - - // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option? - // or is that only in bounds GEP - // REVIEW: Should this be AggregatePointerValue? - fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { - unsafe { - BasicValueEnum::new(LLVMConstExtractValue( - self.as_value_ref(), - indexes.as_mut_ptr(), - indexes.len() as u32, - )) - } - } - - // SubTypes: value should really be T in self: VectorValue I think - fn const_insert_value>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { - unsafe { - BasicValueEnum::new(LLVMConstInsertValue( - self.as_value_ref(), - value.as_value_ref(), - indexes.as_mut_ptr(), - indexes.len() as u32, - )) - } - } } /// Represents a basic value, which can be used both by itself, or in an `AggregateValue`. From 47bd6a02cc329cd4d2af6475f5aa43b8e1ed4894 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 17 Nov 2022 15:34:48 +0100 Subject: [PATCH 07/34] Make 'inkwell' compile with LLVM 15 1. Remove the `LLVMConst*` function family 2. Remove some optimization passes, including those for coroutines 3. Update the `AtomicRMWBinOp` enum (cherry picked from commit 2a5b19311abca87a4fcb468af524ed3ac16b7a38) --- .idea/inkwell.iml | 14 +++++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ .idea/workspace.xml | 56 +++++++++++++++++++ src/lib.rs | 10 ++++ src/module.rs | 71 +++++++++++++++++++++++- src/passes.rs | 113 +------------------------------------- src/values/float_value.rs | 24 +------- src/values/int_value.rs | 35 ++---------- src/values/traits.rs | 26 --------- 10 files changed, 173 insertions(+), 190 deletions(-) create mode 100644 .idea/inkwell.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml diff --git a/.idea/inkwell.iml b/.idea/inkwell.iml new file mode 100644 index 00000000000..ffadb4d8eb8 --- /dev/null +++ b/.idea/inkwell.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000000..95a488c0689 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000000..35eb1ddfbbc --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 00000000000..55882d1a663 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + { + "keyToString": { + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "last_opened_file_path": "/home/hedgar/src/llvm/inkwell", + "org.rust.cargo.project.model.PROJECT_DISCOVERY": "true", + "org.rust.disableDetachedFileInspection/home/hedgar/src/llvm/inkwell/src/builder.rs": "true", + "org.rust.disableDetachedFileInspection/home/hedgar/src/llvm/inkwell/src/support/mod.rs": "true" + } +} + + + + + + + \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 764d7789722..7ddf7fc7bef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,6 +331,16 @@ pub enum AtomicRMWBinOp { #[llvm_versions(10.0..=latest)] #[llvm_variant(LLVMAtomicRMWBinOpFSub)] FSub, + + /// Sets memory to the float-typed-greater of the value provided and the value in memory. Returns the value that was in memory. + #[llvm_versions(15.0..=latest)] + #[llvm_variant(LLVMAtomicRMWBinOpFMax)] + FMax, + + /// Sets memory to the float-typed-lesser of the value provided and the value in memory. Returns the value that was in memory. + #[llvm_versions(15.0..=latest)] + #[llvm_variant(LLVMAtomicRMWBinOpFMin)] + FMin, } /// Defines the optimization level used to compile a `Module`. diff --git a/src/module.rs b/src/module.rs index 261cd6b20d6..39c68aeafe9 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1104,7 +1104,76 @@ impl<'ctx> Module<'ctx> { unsafe { Some(GlobalValue::new(value)) } } - /// Creates a new `Module` from a `MemoryBuffer`. + /// Creates a new `Module` from a `MemoryBuffer` with IR. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::module::Module; + /// use inkwell::memory_buffer::MemoryBuffer; + /// use std::path::Path; + /// + /// let path = Path::new("foo/bar.ll"); + /// let context = Context::create(); + /// let buffer = MemoryBuffer::create_from_file(&path).unwrap(); + /// let module = Module::parse_ir_from_buffer(&buffer, &context); + /// + /// assert_eq!(*module.unwrap().get_context(), context); + /// + /// ``` + pub fn parse_ir_from_buffer( + buffer: &MemoryBuffer, + context: &'ctx Context, + ) -> Result { + let mut module = MaybeUninit::uninit(); + let mut err_string = MaybeUninit::uninit(); + + let success = unsafe { + LLVMParseIRInContext( + context.context.0, + buffer.memory_buffer, + module.as_mut_ptr(), + err_string.as_mut_ptr(), + ) + }; + + if success != 0 { + let err_string = unsafe { err_string.assume_init() }; + return Err(unsafe { LLVMString::new(err_string) }); + } + + let module = unsafe { module.assume_init() }; + + Ok(unsafe { Module::new(module) }) + } + + /// A convenience function for creating a `Module` from an IR file for a given context. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::module::Module; + /// use std::path::Path; + /// + /// let path = Path::new("foo/bar.ll"); + /// let context = Context::create(); + /// let module = Module::parse_ir_from_path(&path, &context); + /// + /// assert_eq!(*module.unwrap().get_context(), context); + /// + /// ``` + pub fn parse_ir_from_path>( + path: P, + context: &'ctx Context, + ) -> Result { + let buffer = MemoryBuffer::create_from_file(path.as_ref())?; + + Self::parse_ir_from_buffer(&buffer, &context) + } + + /// Creates a new `Module` from a `MemoryBuffer` with bitcode. /// /// # Example /// diff --git a/src/passes.rs b/src/passes.rs index 118b1fa1e08..a562758d840 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -12,14 +12,14 @@ use llvm_sys::prelude::{LLVMPassManagerRef, LLVMPassRegistryRef}; #[llvm_versions(10.0..=latest)] use llvm_sys::transforms::ipo::LLVMAddMergeFunctionsPass; use llvm_sys::transforms::ipo::{ - LLVMAddAlwaysInlinerPass, LLVMAddArgumentPromotionPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, + LLVMAddAlwaysInlinerPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, LLVMAddFunctionAttrsPass, LLVMAddFunctionInliningPass, LLVMAddGlobalDCEPass, LLVMAddGlobalOptimizerPass, LLVMAddIPSCCPPass, LLVMAddInternalizePass, LLVMAddPruneEHPass, LLVMAddStripDeadPrototypesPass, LLVMAddStripSymbolsPass, }; use llvm_sys::transforms::pass_manager_builder::{ LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderPopulateFunctionPassManager, - LLVMPassManagerBuilderPopulateLTOPassManager, LLVMPassManagerBuilderPopulateModulePassManager, + LLVMPassManagerBuilderPopulateModulePassManager, LLVMPassManagerBuilderRef, LLVMPassManagerBuilderSetDisableSimplifyLibCalls, LLVMPassManagerBuilderSetDisableUnitAtATime, LLVMPassManagerBuilderSetDisableUnrollLoops, LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderSetSizeLevel, @@ -31,7 +31,7 @@ use llvm_sys::transforms::scalar::{ LLVMAddDeadStoreEliminationPass, LLVMAddDemoteMemoryToRegisterPass, LLVMAddEarlyCSEPass, LLVMAddGVNPass, LLVMAddIndVarSimplifyPass, LLVMAddInstructionCombiningPass, LLVMAddJumpThreadingPass, LLVMAddLICMPass, LLVMAddLoopDeletionPass, LLVMAddLoopIdiomPass, LLVMAddLoopRerollPass, LLVMAddLoopRotatePass, LLVMAddLoopUnrollPass, - LLVMAddLoopUnswitchPass, LLVMAddLowerExpectIntrinsicPass, LLVMAddMemCpyOptPass, LLVMAddMergedLoadStoreMotionPass, + LLVMAddLowerExpectIntrinsicPass, LLVMAddMemCpyOptPass, LLVMAddMergedLoadStoreMotionPass, LLVMAddPartiallyInlineLibCallsPass, LLVMAddReassociatePass, LLVMAddSCCPPass, LLVMAddScalarReplAggregatesPass, LLVMAddScalarReplAggregatesPassSSA, LLVMAddScalarReplAggregatesPassWithThreshold, LLVMAddScalarizerPass, LLVMAddScopedNoAliasAAPass, LLVMAddSimplifyLibCallsPass, LLVMAddTailCallEliminationPass, @@ -162,37 +162,6 @@ impl PassManagerBuilder { pub fn populate_module_pass_manager(&self, pass_manager: &PassManager) { unsafe { LLVMPassManagerBuilderPopulateModulePassManager(self.pass_manager_builder, pass_manager.pass_manager) } } - - /// Populates a PassManager with the expectation of link time - /// optimization transformations. - /// - /// # Example - /// - /// ```no_run - /// use inkwell::OptimizationLevel::Aggressive; - /// use inkwell::passes::{PassManager, PassManagerBuilder}; - /// use inkwell::targets::{InitializationConfig, Target}; - /// - /// let config = InitializationConfig::default(); - /// Target::initialize_native(&config).unwrap(); - /// let pass_manager_builder = PassManagerBuilder::create(); - /// - /// pass_manager_builder.set_optimization_level(Aggressive); - /// - /// let lpm = PassManager::create(()); - /// - /// pass_manager_builder.populate_lto_pass_manager(&lpm, false, false); - /// ``` - pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) { - unsafe { - LLVMPassManagerBuilderPopulateLTOPassManager( - self.pass_manager_builder, - pass_manager.pass_manager, - internalize as i32, - run_inliner as i32, - ) - } - } } impl Drop for PassManagerBuilder { @@ -282,28 +251,6 @@ impl PassManager { unsafe { input.run_in_pass_manager(self) } } - /// This pass promotes "by reference" arguments to be "by value" arguments. - /// In practice, this means looking for internal functions that have pointer - /// arguments. If it can prove, through the use of alias analysis, that an - /// argument is only loaded, then it can pass the value into the function - /// instead of the address of the value. This can cause recursive simplification - /// of code and lead to the elimination of allocas (especially in C++ template - /// code like the STL). - /// - /// This pass also handles aggregate arguments that are passed into a function, - /// scalarizing them if the elements of the aggregate are only loaded. Note that - /// it refuses to scalarize aggregates which would require passing in more than - /// three operands to the function, because passing thousands of operands for a - /// large array or structure is unprofitable! - /// - /// Note that this transformation could also be done for arguments that are - /// only stored to (returning the value instead), but does not currently. - /// This case would be best handled when and if LLVM starts supporting multiple - /// return values from functions. - pub fn add_argument_promotion_pass(&self) { - unsafe { LLVMAddArgumentPromotionPass(self.pass_manager) } - } - /// Merges duplicate global constants together into a single constant that is /// shared. This is useful because some passes (i.e., TraceValues) insert a lot /// of string constants into the program, regardless of whether or not an existing @@ -699,32 +646,6 @@ impl PassManager { unsafe { LLVMAddLoopUnrollPass(self.pass_manager) } } - /// This pass transforms loops that contain branches on - /// loop-invariant conditions to have multiple loops. - /// For example, it turns the left into the right code: - /// - /// ```c - /// for (...) if (lic) - /// A for (...) - /// if (lic) A; B; C - /// B else - /// C for (...) - /// A; C - /// ``` - /// - /// This can increase the size of the code exponentially - /// (doubling it every time a loop is unswitched) so we - /// only unswitch if the resultant code will be smaller - /// than a threshold. - /// - /// This pass expects [LICM](https://llvm.org/docs/Passes.html#passes-licm) - /// to be run before it to hoist invariant conditions - /// out of the loop, to make the unswitching opportunity - /// obvious. - pub fn add_loop_unswitch_pass(&self) { - unsafe { LLVMAddLoopUnswitchPass(self.pass_manager) } - } - /// This pass performs various transformations related /// to eliminating memcpy calls, or transforming sets /// of stores into memsets. @@ -1007,34 +928,6 @@ impl PassManager { unsafe { LLVMAddLoopUnrollAndJamPass(self.pass_manager) } } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_early_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroEarlyPass; - - unsafe { LLVMAddCoroEarlyPass(self.pass_manager) } - } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_split_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroSplitPass; - - unsafe { LLVMAddCoroSplitPass(self.pass_manager) } - } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_elide_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroElidePass; - - unsafe { LLVMAddCoroElidePass(self.pass_manager) } - } - - #[llvm_versions(8.0..=latest)] - pub fn add_coroutine_cleanup_pass(&self) { - use llvm_sys::transforms::coroutines::LLVMAddCoroCleanupPass; - - unsafe { LLVMAddCoroCleanupPass(self.pass_manager) } - } } impl Drop for PassManager { diff --git a/src/values/float_value.rs b/src/values/float_value.rs index c3ba6c85dc1..b494dd5bef2 100644 --- a/src/values/float_value.rs +++ b/src/values/float_value.rs @@ -1,6 +1,6 @@ use llvm_sys::core::{ - LLVMConstFAdd, LLVMConstFCmp, LLVMConstFDiv, LLVMConstFMul, LLVMConstFNeg, LLVMConstFPCast, LLVMConstFPExt, - LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc, LLVMConstFRem, LLVMConstFSub, LLVMConstRealGetDouble, + LLVMConstFCmp, LLVMConstFNeg, LLVMConstFPCast, LLVMConstFPExt, + LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc, LLVMConstRealGetDouble, }; use llvm_sys::prelude::LLVMValueRef; @@ -64,26 +64,6 @@ impl<'ctx> FloatValue<'ctx> { unsafe { FloatValue::new(LLVMConstFNeg(self.as_value_ref())) } } - pub fn const_add(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFAdd(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_sub(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFSub(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_mul(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFMul(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_div(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_remainder(self, rhs: FloatValue<'ctx>) -> Self { - unsafe { FloatValue::new(LLVMConstFRem(self.as_value_ref(), rhs.as_value_ref())) } - } - pub fn const_cast(self, float_type: FloatType<'ctx>) -> Self { unsafe { FloatValue::new(LLVMConstFPCast(self.as_value_ref(), float_type.as_type_ref())) } } diff --git a/src/values/int_value.rs b/src/values/int_value.rs index 5e4846569a0..ebb992afa40 100644 --- a/src/values/int_value.rs +++ b/src/values/int_value.rs @@ -1,12 +1,10 @@ -#[llvm_versions(4.0..=latest)] -use llvm_sys::core::LLVMConstExactUDiv; use llvm_sys::core::{ - LLVMConstAShr, LLVMConstAdd, LLVMConstAnd, LLVMConstBitCast, LLVMConstExactSDiv, LLVMConstICmp, LLVMConstIntCast, + LLVMConstAShr, LLVMConstAdd, LLVMConstAnd, LLVMConstBitCast, LLVMConstICmp, LLVMConstIntCast, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr, LLVMConstLShr, LLVMConstMul, LLVMConstNSWAdd, LLVMConstNSWMul, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWMul, - LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSDiv, LLVMConstSExt, - LLVMConstSExtOrBitCast, LLVMConstSIToFP, LLVMConstSRem, LLVMConstSelect, LLVMConstShl, LLVMConstSub, - LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstUDiv, LLVMConstUIToFP, LLVMConstURem, LLVMConstXor, + LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSExt, + LLVMConstSExtOrBitCast, LLVMConstSIToFP, LLVMConstSelect, LLVMConstShl, LLVMConstSub, + LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstUIToFP, LLVMConstXor, LLVMConstZExt, LLVMConstZExtOrBitCast, LLVMIsAConstantInt, }; use llvm_sys::prelude::LLVMValueRef; @@ -120,31 +118,6 @@ impl<'ctx> IntValue<'ctx> { unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) } } - pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - #[llvm_versions(4.0..=latest)] - pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) } - } - - pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self { - unsafe { IntValue::new(LLVMConstSRem(self.as_value_ref(), rhs.as_value_ref())) } - } - pub fn const_and(self, rhs: IntValue<'ctx>) -> Self { unsafe { IntValue::new(LLVMConstAnd(self.as_value_ref(), rhs.as_value_ref())) } } diff --git a/src/values/traits.rs b/src/values/traits.rs index 366f74e9f18..957671fa673 100644 --- a/src/values/traits.rs +++ b/src/values/traits.rs @@ -1,4 +1,3 @@ -use llvm_sys::core::{LLVMConstExtractValue, LLVMConstInsertValue}; use llvm_sys::prelude::LLVMValueRef; use std::fmt::Debug; @@ -51,31 +50,6 @@ pub trait AggregateValue<'ctx>: BasicValue<'ctx> { fn as_aggregate_value_enum(&self) -> AggregateValueEnum<'ctx> { unsafe { AggregateValueEnum::new(self.as_value_ref()) } } - - // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option? - // or is that only in bounds GEP - // REVIEW: Should this be AggregatePointerValue? - fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { - unsafe { - BasicValueEnum::new(LLVMConstExtractValue( - self.as_value_ref(), - indexes.as_mut_ptr(), - indexes.len() as u32, - )) - } - } - - // SubTypes: value should really be T in self: VectorValue I think - fn const_insert_value>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { - unsafe { - BasicValueEnum::new(LLVMConstInsertValue( - self.as_value_ref(), - value.as_value_ref(), - indexes.as_mut_ptr(), - indexes.len() as u32, - )) - } - } } /// Represents a basic value, which can be used both by itself, or in an `AggregateValue`. From 82ca8f554f7490ce7a57d25a7a8bed80d4fde485 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sat, 19 Nov 2022 00:25:20 +0100 Subject: [PATCH 08/34] Support load2 and gep2 --- src/builder.rs | 137 ++++++++++++++++------------------- src/lib.rs | 12 +-- src/module.rs | 10 +-- src/passes.rs | 14 ++-- src/support/mod.rs | 5 +- src/targets.rs | 5 +- src/types/enums.rs | 14 +++- src/values/float_value.rs | 4 +- src/values/int_value.rs | 7 +- src/values/metadata_value.rs | 7 +- 10 files changed, 101 insertions(+), 114 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 9f66eebe57f..a426ee14959 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -38,11 +38,11 @@ use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; use crate::support::to_c_str; -use crate::types::{BasicType, AsTypeRef, PointerType, AnyType, IntMathType, PointerMathType, FloatMathType}; +use crate::types::{AnyType, AsTypeRef, BasicType, FloatMathType, IntMathType, PointerMathType, PointerType}; use crate::values::{ - AggregateValue, AggregateValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, - CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, InstructionValue, IntMathValue, - IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, AnyValue, AnyValueEnum, + AggregateValue, AggregateValueEnum, AnyValue, AnyValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, + BasicValueEnum, CallSiteValue, CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, + InstructionValue, IntMathValue, IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, }; #[cfg(feature = "internal-getters")] use crate::LLVMReference; @@ -633,6 +633,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(4.0..=13.0)] pub unsafe fn build_gep( &self, ptr: PointerValue<'ctx>, @@ -643,43 +644,34 @@ impl<'ctx> Builder<'ctx> { let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] - let value = LLVMBuildGEP2( + let value = LLVMBuildGEP( 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(), ); - #[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", - ))] - let value = LLVMBuildGEP( + 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(14.0..=latest)] + pub unsafe fn build_gep2>( + &self, + ty: T, + ptr: PointerValue<'ctx>, + ordered_indexes: &[IntValue<'ctx>], + name: &str, + ) -> PointerValue<'ctx> { + let c_string = to_c_str(name); + + let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); + + let value = LLVMBuildGEP2( self.builder, + ty.as_type_ref(), ptr.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, @@ -987,49 +979,49 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&pointee)); /// ``` + #[llvm_versions(4.0..=13.0)] pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] - let value = unsafe { - LLVMBuildLoad2( - self.builder, - ptr.get_type().get_element_type().as_type_ref(), - ptr.as_value_ref(), - c_string.as_ptr(), - ) - }; - - #[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", - ))] let value = unsafe { LLVMBuildLoad(self.builder, ptr.as_value_ref(), c_string.as_ptr()) }; unsafe { BasicValueEnum::new(value) } } + /// Builds a load2 instruction. It allows you to retrieve a value of type `T` from a pointer to a type `T`. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::AddressSpace; + /// + /// // Builds a function which takes an i32 pointer and returns the pointed at i32. + /// let context = Context::create(); + /// let module = context.create_module("ret"); + /// let builder = context.create_builder(); + /// let i32_type = context.i32_type(); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); + /// let fn_type = i32_type.fn_type(&[i32_ptr_type.into()], false); + /// let fn_value = module.add_function("ret", fn_type, None); + /// let entry = context.append_basic_block(fn_value, "entry"); + /// let i32_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value(); + /// + /// builder.position_at_end(entry); + /// + /// let pointee = builder.build_load2(i32_type, i32_ptr_param, "load2"); + /// + /// builder.build_return(Some(&pointee)); + /// ``` + #[llvm_versions(14.0..=latest)] + pub fn build_load2>(&self, ty: T, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { + let c_string = to_c_str(name); + + let value = unsafe { LLVMBuildLoad2(self.builder, ty.as_type_ref(), ptr.as_value_ref(), c_string.as_ptr()) }; + + unsafe { BasicValueEnum::new(value) } + } + // TODOC: Stack allocation pub fn build_alloca>(&self, ty: T, name: &str) -> PointerValue<'ctx> { let c_string = to_c_str(name); @@ -1341,14 +1333,7 @@ impl<'ctx> Builder<'ctx> { let c_string = to_c_str(name); let value = unsafe { LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr()) }; - let value = unsafe { - LLVMBuildBitCast( - self.builder, - val.as_value_ref(), - ty.as_type_ref(), - c_string.as_ptr(), - ) - }; + let value = unsafe { LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr()) }; unsafe { AnyValueEnum::new(value) } } diff --git a/src/lib.rs b/src/lib.rs index 96d9850cc14..0ff4639b1b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,12 +110,12 @@ assert_unique_used_features! {"llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8 /// Defines the abstract LLVM address space. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum AddressSpace { - Zero = 0, - One = 1, - Two = 2, - Three = 3, - Four = 4, - Five = 5, + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, } impl TryFrom for AddressSpace { diff --git a/src/module.rs b/src/module.rs index d61868d990a..5df4b2ae890 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1123,10 +1123,7 @@ impl<'ctx> Module<'ctx> { /// assert_eq!(*module.unwrap().get_context(), context); /// /// ``` - pub fn parse_ir_from_buffer( - buffer: &MemoryBuffer, - context: &'ctx Context, - ) -> Result { + pub fn parse_ir_from_buffer(buffer: &MemoryBuffer, context: &'ctx Context) -> Result { let mut module = MaybeUninit::uninit(); let mut err_string = MaybeUninit::uninit(); @@ -1165,10 +1162,7 @@ impl<'ctx> Module<'ctx> { /// assert_eq!(*module.unwrap().get_context(), context); /// /// ``` - pub fn parse_ir_from_path>( - path: P, - context: &'ctx Context, - ) -> Result { + pub fn parse_ir_from_path>(path: P, context: &'ctx Context) -> Result { let buffer = MemoryBuffer::create_from_file(path.as_ref())?; Self::parse_ir_from_buffer(&buffer, &context) diff --git a/src/passes.rs b/src/passes.rs index a562758d840..1defb0fdbf6 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -12,17 +12,15 @@ use llvm_sys::prelude::{LLVMPassManagerRef, LLVMPassRegistryRef}; #[llvm_versions(10.0..=latest)] use llvm_sys::transforms::ipo::LLVMAddMergeFunctionsPass; use llvm_sys::transforms::ipo::{ - LLVMAddAlwaysInlinerPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, - LLVMAddFunctionAttrsPass, LLVMAddFunctionInliningPass, LLVMAddGlobalDCEPass, LLVMAddGlobalOptimizerPass, - LLVMAddIPSCCPPass, LLVMAddInternalizePass, LLVMAddPruneEHPass, LLVMAddStripDeadPrototypesPass, - LLVMAddStripSymbolsPass, + LLVMAddAlwaysInlinerPass, LLVMAddConstantMergePass, LLVMAddDeadArgEliminationPass, LLVMAddFunctionAttrsPass, + LLVMAddFunctionInliningPass, LLVMAddGlobalDCEPass, LLVMAddGlobalOptimizerPass, LLVMAddIPSCCPPass, + LLVMAddInternalizePass, LLVMAddPruneEHPass, LLVMAddStripDeadPrototypesPass, LLVMAddStripSymbolsPass, }; use llvm_sys::transforms::pass_manager_builder::{ LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderPopulateFunctionPassManager, - LLVMPassManagerBuilderPopulateModulePassManager, - LLVMPassManagerBuilderRef, LLVMPassManagerBuilderSetDisableSimplifyLibCalls, - LLVMPassManagerBuilderSetDisableUnitAtATime, LLVMPassManagerBuilderSetDisableUnrollLoops, - LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderSetSizeLevel, + LLVMPassManagerBuilderPopulateModulePassManager, LLVMPassManagerBuilderRef, + LLVMPassManagerBuilderSetDisableSimplifyLibCalls, LLVMPassManagerBuilderSetDisableUnitAtATime, + LLVMPassManagerBuilderSetDisableUnrollLoops, LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderSetSizeLevel, LLVMPassManagerBuilderUseInlinerWithThreshold, }; use llvm_sys::transforms::scalar::{ diff --git a/src/support/mod.rs b/src/support/mod.rs index 016f9e6acec..d042dac67d0 100644 --- a/src/support/mod.rs +++ b/src/support/mod.rs @@ -125,10 +125,7 @@ pub unsafe fn shutdown_llvm() { } pub fn parse_command_line_options(argc: i32, argv: &[&str], overview: &str) { - let argv: Vec<*const ::libc::c_char> = argv - .iter() - .map(|arg| to_c_str(arg).as_ptr()) - .collect(); + let argv: Vec<*const ::libc::c_char> = argv.iter().map(|arg| to_c_str(arg).as_ptr()).collect(); let overview = to_c_str(overview); unsafe { diff --git a/src/targets.rs b/src/targets.rs index 102f1ceee99..e30420d87c3 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -756,9 +756,8 @@ impl Target { #[llvm_versions(11.0..=latest)] pub fn initialize_syncvm(config: &InitializationConfig) { use llvm_sys::target::{ - LLVMInitializeSyncVMAsmParser, LLVMInitializeSyncVMAsmPrinter, - LLVMInitializeSyncVMDisassembler, LLVMInitializeSyncVMTarget, - LLVMInitializeSyncVMTargetInfo, LLVMInitializeSyncVMTargetMC, + LLVMInitializeSyncVMAsmParser, LLVMInitializeSyncVMAsmPrinter, LLVMInitializeSyncVMDisassembler, + LLVMInitializeSyncVMTarget, LLVMInitializeSyncVMTargetInfo, LLVMInitializeSyncVMTargetMC, }; if config.base { diff --git a/src/types/enums.rs b/src/types/enums.rs index 2dca319826c..fc232427acb 100644 --- a/src/types/enums.rs +++ b/src/types/enums.rs @@ -237,7 +237,12 @@ impl<'ctx> AnyTypeEnum<'ctx> { LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)), LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Metadata type is not supported as AnyType."), LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"), - #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(any( + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" + ))] LLVMTypeKind::LLVMX86_AMXTypeKind => panic!("FIXME: Unsupported type: AMX"), LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"), } @@ -406,7 +411,12 @@ impl<'ctx> BasicTypeEnum<'ctx> { // see https://llvm.org/docs/LangRef.html#x86-mmx-type LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"), // see https://llvm.org/docs/LangRef.html#x86-amx-type - #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(any( + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" + ))] LLVMTypeKind::LLVMX86_AMXTypeKind => unreachable!("Unsupported basic type: AMX"), LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"), LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"), diff --git a/src/values/float_value.rs b/src/values/float_value.rs index b494dd5bef2..5881c9cdd11 100644 --- a/src/values/float_value.rs +++ b/src/values/float_value.rs @@ -1,6 +1,6 @@ use llvm_sys::core::{ - LLVMConstFCmp, LLVMConstFNeg, LLVMConstFPCast, LLVMConstFPExt, - LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc, LLVMConstRealGetDouble, + LLVMConstFCmp, LLVMConstFNeg, LLVMConstFPCast, LLVMConstFPExt, LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc, + LLVMConstRealGetDouble, }; use llvm_sys::prelude::LLVMValueRef; diff --git a/src/values/int_value.rs b/src/values/int_value.rs index ebb992afa40..4511da71e0a 100644 --- a/src/values/int_value.rs +++ b/src/values/int_value.rs @@ -2,10 +2,9 @@ use llvm_sys::core::{ LLVMConstAShr, LLVMConstAdd, LLVMConstAnd, LLVMConstBitCast, LLVMConstICmp, LLVMConstIntCast, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr, LLVMConstLShr, LLVMConstMul, LLVMConstNSWAdd, LLVMConstNSWMul, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWMul, - LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSExt, - LLVMConstSExtOrBitCast, LLVMConstSIToFP, LLVMConstSelect, LLVMConstShl, LLVMConstSub, - LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstUIToFP, LLVMConstXor, - LLVMConstZExt, LLVMConstZExtOrBitCast, LLVMIsAConstantInt, + LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSExt, LLVMConstSExtOrBitCast, + LLVMConstSIToFP, LLVMConstSelect, LLVMConstShl, LLVMConstSub, LLVMConstTrunc, LLVMConstTruncOrBitCast, + LLVMConstUIToFP, LLVMConstXor, LLVMConstZExt, LLVMConstZExtOrBitCast, LLVMIsAConstantInt, }; use llvm_sys::prelude::LLVMValueRef; diff --git a/src/values/metadata_value.rs b/src/values/metadata_value.rs index b645fe22dbb..3a850b7f4dc 100644 --- a/src/values/metadata_value.rs +++ b/src/values/metadata_value.rs @@ -32,7 +32,12 @@ pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 26; pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 28; #[cfg(any(feature = "llvm10-0", feature = "llvm11-0"))] pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 30; -#[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] +#[cfg(any( + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" +))] pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 31; #[derive(PartialEq, Eq, Clone, Copy, Hash)] From 713880157f226174183684a5896c50fee7a8959c Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sat, 19 Nov 2022 17:03:00 +0200 Subject: [PATCH 09/34] Support the rest of GEPs and ptr_diff --- src/builder.rs | 222 +++++++++++++++++++++++----------------- src/context.rs | 3 +- src/module.rs | 2 +- src/values/ptr_value.rs | 85 +++++---------- 4 files changed, 155 insertions(+), 157 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index a426ee14959..eaaf5549ad1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -633,7 +633,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(4.0..=13.0)] + #[llvm_versions(4.0..14.0)] pub unsafe fn build_gep( &self, ptr: PointerValue<'ctx>, @@ -658,7 +658,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.0..=latest)] - pub unsafe fn build_gep2>( + pub unsafe fn build_gep_2>( &self, ty: T, ptr: PointerValue<'ctx>, @@ -684,6 +684,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(4.0..14.0)] pub unsafe fn build_in_bounds_gep( &self, ptr: PointerValue<'ctx>, @@ -694,43 +695,35 @@ impl<'ctx> Builder<'ctx> { let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] - let value = LLVMBuildInBoundsGEP2( + let value = LLVMBuildInBoundsGEP( 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(), ); - #[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", - ))] - let value = LLVMBuildInBoundsGEP( + PointerValue::new(value) + } + + // 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.0..=latest)] + pub unsafe fn build_in_bounds_gep_2>( + &self, + ty: T, + ptr: PointerValue<'ctx>, + ordered_indexes: &[IntValue<'ctx>], + name: &str, + ) -> PointerValue<'ctx> { + let c_string = to_c_str(name); + + let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); + + let value = LLVMBuildInBoundsGEP2( self.builder, + ty.as_type_ref(), ptr.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, @@ -773,6 +766,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(4.0..14.0)] pub fn build_struct_gep(&self, ptr: PointerValue<'ctx>, index: u32, name: &str) -> Result, ()> { let ptr_ty = ptr.get_type(); let pointee_ty = ptr_ty.get_element_type(); @@ -789,44 +783,71 @@ impl<'ctx> Builder<'ctx> { let c_string = to_c_str(name); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] + let value = unsafe { LLVMBuildStructGEP(self.builder, ptr.as_value_ref(), index, c_string.as_ptr()) }; + + unsafe { Ok(PointerValue::new(value)) } + } + + /// Builds a GEP instruction on a struct pointer. Returns `Err(())` if input `PointerValue` doesn't + /// point to a struct or if index is out of bounds. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::AddressSpace; + /// use inkwell::context::Context; + /// + /// let context = Context::create(); + /// let builder = context.create_builder(); + /// let module = context.create_module("struct_gep"); + /// let void_type = context.void_type(); + /// let i32_ty = context.i32_type(); + /// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Zero); + /// let field_types = &[i32_ty.into(), i32_ty.into()]; + /// let struct_ty = context.struct_type(field_types, false); + /// let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::Zero); + /// 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); + /// let entry = context.append_basic_block(fn_value, "entry"); + /// + /// builder.position_at_end(entry); + /// + /// let i32_ptr = fn_value.get_first_param().unwrap().into_pointer_value(); + /// let struct_ptr = fn_value.get_last_param().unwrap().into_pointer_value(); + /// + /// assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 0, "struct_gep").is_err()); + /// assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 10, "struct_gep").is_err()); + /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 0, "struct_gep").is_ok()); + /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 1, "struct_gep").is_ok()); + /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 2, "struct_gep").is_err()); + /// ``` + #[llvm_versions(14.0..=latest)] + pub fn build_struct_gep_2>(&self, ty: T, ptr: PointerValue<'ctx>, index: u32, name: &str) -> Result, ()> { + let ptr_ty = ptr.get_type(); + let pointee_ty = ptr_ty.get_element_type(); + + if !pointee_ty.is_struct_type() { + return Err(()); + } + + let struct_ty = pointee_ty.into_struct_type(); + + if index >= struct_ty.count_fields() { + return Err(()); + } + + let c_string = to_c_str(name); + let value = unsafe { LLVMBuildStructGEP2( self.builder, - ptr.get_type().get_element_type().as_type_ref(), + ty.as_type_ref(), ptr.as_value_ref(), index, c_string.as_ptr(), ) }; - #[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", - ))] - let value = unsafe { LLVMBuildStructGEP(self.builder, ptr.as_value_ref(), index, c_string.as_ptr()) }; - unsafe { Ok(PointerValue::new(value)) } } @@ -855,6 +876,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_ptr_diff(i32_ptr_param1, i32_ptr_param2, "diff"); /// builder.build_return(None); /// ``` + #[llvm_versions(4.0..14.0)] pub fn build_ptr_diff( &self, lhs_ptr: PointerValue<'ctx>, @@ -862,46 +884,57 @@ impl<'ctx> Builder<'ctx> { name: &str, ) -> IntValue<'ctx> { let c_string = to_c_str(name); - - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] - let value = unsafe { - LLVMBuildPtrDiff2( + let value = unsafe { + LLVMBuildPtrDiff( self.builder, - lhs_ptr.get_type().as_type_ref(), lhs_ptr.as_value_ref(), rhs_ptr.as_value_ref(), c_string.as_ptr(), ) }; - #[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", - ))] + unsafe { IntValue::new(value) } + } + + /// Builds an instruction which calculates the difference of two pointers. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::AddressSpace; + /// + /// // Builds a function which diffs two pointers + /// let context = Context::create(); + /// let module = context.create_module("ret"); + /// let builder = context.create_builder(); + /// let void_type = context.void_type(); + /// let i32_type = context.i32_type(); + /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); + /// 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); + /// let entry = context.append_basic_block(fn_value, "entry"); + /// let i32_ptr_param1 = fn_value.get_first_param().unwrap().into_pointer_value(); + /// let i32_ptr_param2 = fn_value.get_nth_param(1).unwrap().into_pointer_value(); + /// + /// builder.position_at_end(entry); + /// builder.build_ptr_diff_2(i32_ptr_type, i32_ptr_param1, i32_ptr_param2, "diff"); + /// builder.build_return(None); + /// ``` + #[llvm_versions(14.0..=latest)] + pub fn build_ptr_diff_2>( + &self, + ty: T, + lhs_ptr: PointerValue<'ctx>, + rhs_ptr: PointerValue<'ctx>, + name: &str, + ) -> IntValue<'ctx> { + let c_string = to_c_str(name); + let value = unsafe { - LLVMBuildPtrDiff( + LLVMBuildPtrDiff2( self.builder, + ty.as_type_ref(), lhs_ptr.as_value_ref(), rhs_ptr.as_value_ref(), c_string.as_ptr(), @@ -979,7 +1012,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&pointee)); /// ``` - #[llvm_versions(4.0..=13.0)] + #[llvm_versions(4.0..14.0)] pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); @@ -1009,12 +1042,12 @@ impl<'ctx> Builder<'ctx> { /// /// builder.position_at_end(entry); /// - /// let pointee = builder.build_load2(i32_type, i32_ptr_param, "load2"); + /// let pointee = builder.build_load_2(i32_type, i32_ptr_param, "load2"); /// /// builder.build_return(Some(&pointee)); /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_load2>(&self, ty: T, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { + pub fn build_load_2>(&self, ty: T, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); let value = unsafe { LLVMBuildLoad2(self.builder, ty.as_type_ref(), ptr.as_value_ref(), c_string.as_ptr()) }; @@ -1331,7 +1364,6 @@ impl<'ctx> Builder<'ctx> { V: AnyValue<'ctx>, { let c_string = to_c_str(name); - let value = unsafe { LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr()) }; let value = unsafe { LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr()) }; diff --git a/src/context.rs b/src/context.rs index 7a0a118f18a..ed2bf558dc8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -48,8 +48,7 @@ use crate::AddressSpace; use crate::LLVMReference; use std::marker::PhantomData; -use std::mem::{forget, ManuallyDrop}; -use std::ops::Deref; +use std::mem::forget; use std::ptr; use std::thread_local; diff --git a/src/module.rs b/src/module.rs index 5df4b2ae890..9c3d24494cc 100644 --- a/src/module.rs +++ b/src/module.rs @@ -23,7 +23,7 @@ use llvm_sys::execution_engine::{ LLVMCreateExecutionEngineForModule, LLVMCreateInterpreterForModule, LLVMCreateJITCompilerForModule, }; use llvm_sys::ir_reader::LLVMParseIRInContext; -use llvm_sys::prelude::{LLVMModuleRef, LLVMTypeRef, LLVMValueRef}; +use llvm_sys::prelude::{LLVMModuleRef, LLVMValueRef}; #[llvm_versions(13.0..=latest)] use llvm_sys::transforms::pass_builder::LLVMRunPasses; use llvm_sys::LLVMLinkage; diff --git a/src/values/ptr_value.rs b/src/values/ptr_value.rs index cbaf959f213..fd0a8950236 100644 --- a/src/values/ptr_value.rs +++ b/src/values/ptr_value.rs @@ -10,7 +10,7 @@ use std::convert::TryFrom; use std::ffi::CStr; use std::fmt::{self, Display}; -use crate::types::{AsTypeRef, IntType, PointerType}; +use crate::types::{AsTypeRef, IntType, PointerType, BasicType}; use crate::values::{AsValueRef, InstructionValue, IntValue, Value}; use super::AnyValue; @@ -77,46 +77,30 @@ 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(4.0..14.0)] 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(); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] let value = { - LLVMConstGEP2( - self.get_type().get_element_type().as_type_ref(), + LLVMConstGEP( self.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, ) }; - #[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", - ))] + 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(14.0..=latest)] + pub unsafe fn const_gep_2>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { + let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); + let value = { - LLVMConstGEP( + LLVMConstGEP2( + ty.as_type_ref(), self.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, @@ -127,46 +111,29 @@ 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(4.0..14.0)] 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(); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] let value = { - LLVMConstInBoundsGEP2( - self.get_type().get_element_type().as_type_ref(), + LLVMConstInBoundsGEP( self.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, ) }; - #[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", - ))] + 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(14.0..=latest)] + pub unsafe fn const_in_bounds_gep_2>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { + let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); + let value = { - LLVMConstInBoundsGEP( + LLVMConstInBoundsGEP2( + ty.as_type_ref(), self.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, From 952f33b263af21d10d84771d4b5b4c2307e5dda9 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sat, 19 Nov 2022 17:16:04 +0200 Subject: [PATCH 10/34] Support call_2 and invoke_2 --- src/builder.rs | 240 ++++++++++++++++++++++++++++++---------- src/values/ptr_value.rs | 14 ++- 2 files changed, 190 insertions(+), 64 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index eaaf5549ad1..c53f4c12187 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -38,7 +38,9 @@ use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; use crate::support::to_c_str; -use crate::types::{AnyType, AsTypeRef, BasicType, FloatMathType, IntMathType, PointerMathType, PointerType}; +use crate::types::{ + AnyType, AsTypeRef, BasicType, FloatMathType, FunctionType, IntMathType, PointerMathType, PointerType, +}; use crate::values::{ AggregateValue, AggregateValueEnum, AnyValue, AnyValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, @@ -162,6 +164,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&ret_val)); /// ``` + #[llvm_versions(4.0..14.0)] pub fn build_call(&self, function: F, args: &[BasicMetadataValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx> where F: Into>, @@ -175,23 +178,9 @@ impl<'ctx> Builder<'ctx> { let c_string = to_c_str(name); let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); - #[cfg(not(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", - )))] let value = unsafe { - let fn_ty_ref = callable_value.as_type_ref(); - LLVMBuildCall2( + LLVMBuildCall( self.builder, - fn_ty_ref, fn_val_ref, args.as_mut_ptr(), args.len() as u32, @@ -199,21 +188,65 @@ impl<'ctx> Builder<'ctx> { ) }; - #[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", - ))] + unsafe { CallSiteValue::new(value) } + } + + /// Builds a function call instruction. + /// [`FunctionValue`]s can be implicitly converted into a [`CallableValue`]. + /// See [`CallableValue`] for details on calling a [`PointerValue`] that points to a function. + /// + /// [`FunctionValue`]: crate::values::FunctionValue + /// + /// # Example + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// // A simple function which calls itself: + /// let context = Context::create(); + /// let module = context.create_module("ret"); + /// let builder = context.create_builder(); + /// let i32_type = context.i32_type(); + /// let fn_type = i32_type.fn_type(&[i32_type.into()], false); + /// let fn_value = module.add_function("ret", fn_type, None); + /// let entry = context.append_basic_block(fn_value, "entry"); + /// let i32_arg = fn_value.get_first_param().unwrap(); + /// let md_string = context.metadata_string("a metadata"); + /// + /// builder.position_at_end(entry); + /// + /// let ret_val = builder.build_call_2(fn_type, fn_value, &[i32_arg.into(), md_string.into()], "call") + /// .try_as_basic_value() + /// .left() + /// .unwrap(); + /// + /// builder.build_return(Some(&ret_val)); + /// ``` + #[llvm_versions(14.0..=latest)] + pub fn build_call_2( + &self, + fn_ty: FunctionType<'ctx>, + function: F, + args: &[BasicMetadataValueEnum<'ctx>], + name: &str, + ) -> CallSiteValue<'ctx> + where + F: Into>, + { + let callable_value = function.into(); + let fn_ty_ref = fn_ty.as_type_ref(); + let fn_val_ref = callable_value.as_value_ref(); + + // LLVM gets upset when void return calls are named because they don't return anything + let name = if callable_value.returns_void() { "" } else { name }; + + let c_string = to_c_str(name); + let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); + let value = unsafe { - LLVMBuildCall( + LLVMBuildCall2( self.builder, + fn_ty_ref, fn_val_ref, args.as_mut_ptr(), args.len() as u32, @@ -303,6 +336,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&f32_type.const_zero())); /// } /// ``` + #[llvm_versions(4.0..14.0)] pub fn build_invoke( &self, function: F, @@ -323,25 +357,9 @@ impl<'ctx> Builder<'ctx> { let c_string = to_c_str(name); let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); - // This ugly cfg specification is due to limitation of custom attributes (for more information, see https://github.com/rust-lang/rust/issues/54727). - // Once custom attriutes inside methods are enabled, this should be replaced with #[llvm_version(14.0..=latest)] - #[cfg(not(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", - )))] let value = unsafe { - let fn_ty_ref = callable_value.as_type_ref(); - LLVMBuildInvoke2( + LLVMBuildInvoke( self.builder, - fn_ty_ref, fn_val_ref, args.as_mut_ptr(), args.len() as u32, @@ -351,21 +369,115 @@ impl<'ctx> Builder<'ctx> { ) }; - #[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", - ))] + unsafe { CallSiteValue::new(value) } + } + + /// An invoke is similar to a normal function call, but used to + /// call functions that may throw an exception, and then respond to the exception. + /// + /// When the called function returns normally, the `then` block is evaluated next. If instead + /// the function threw an exception, the `catch` block is entered. The first non-phi + /// instruction of the catch block must be a `landingpad` instruction. See also + /// [`Builder::build_landing_pad`]. + /// + /// The [`add_prune_eh_pass`] turns an invoke into a call when the called function is + /// guaranteed to never throw an exception. + /// + /// [`add_prune_eh_pass`]: crate::passes::PassManager::add_prune_eh_pass + /// + /// This example catches C++ exceptions of type `int`, and returns `0` if an exceptions is thrown. + /// For usage of a cleanup landing pad and the `resume` instruction, see [`Builder::build_resume`] + /// ```no_run + /// use inkwell::context::Context; + /// use inkwell::AddressSpace; + /// use inkwell::module::Linkage; + /// + /// let context = Context::create(); + /// let module = context.create_module("sum"); + /// let builder = context.create_builder(); + /// + /// let f32_type = context.f32_type(); + /// let fn_type = f32_type.fn_type(&[], false); + /// + /// // we will pretend this function can throw an exception + /// let function = module.add_function("bomb", fn_type, None); + /// let basic_block = context.append_basic_block(function, "entry"); + /// + /// builder.position_at_end(basic_block); + /// + /// let pi = f32_type.const_float(::std::f64::consts::PI); + /// + /// builder.build_return(Some(&pi)); + /// + /// let function2 = module.add_function("wrapper", fn_type, None); + /// let basic_block2 = context.append_basic_block(function2, "entry"); + /// + /// builder.position_at_end(basic_block2); + /// + /// let then_block = context.append_basic_block(function2, "then_block"); + /// let catch_block = context.append_basic_block(function2, "catch_block"); + /// + /// let call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); + /// + /// { + /// builder.position_at_end(then_block); + /// + /// // in the then_block, the `call_site` value is defined and can be used + /// let result = call_site.try_as_basic_value().left().unwrap(); + /// + /// builder.build_return(Some(&result)); + /// } + /// + /// { + /// builder.position_at_end(catch_block); + /// + /// // the personality function used by C++ + /// let personality_function = { + /// let name = "__gxx_personality_v0"; + /// let linkage = Some(Linkage::External); + /// + /// module.add_function(name, context.i64_type().fn_type(&[], false), linkage) + /// }; + /// + /// // type of an exception in C++ + /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + /// let i32_type = context.i32_type(); + /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); + /// + /// let null = i8_ptr_type.const_zero(); + /// let res = builder.build_landing_pad(exception_type, personality_function, &[null.into()], false, "res"); + /// + /// // we handle the exception by returning a default value + /// builder.build_return(Some(&f32_type.const_zero())); + /// } + /// ``` + #[llvm_versions(14.0..=latest)] + pub fn build_invoke_2( + &self, + fn_ty: FunctionType<'ctx>, + function: F, + args: &[BasicValueEnum<'ctx>], + then_block: BasicBlock<'ctx>, + catch_block: BasicBlock<'ctx>, + name: &str, + ) -> CallSiteValue<'ctx> + where + F: Into>, + { + let callable_value: CallableValue<'ctx> = function.into(); + let fn_ty_ref = fn_ty.as_type_ref(); + let fn_val_ref = callable_value.as_value_ref(); + + // LLVM gets upset when void return calls are named because they don't return anything + let name = if callable_value.returns_void() { "" } else { name }; + + let c_string = to_c_str(name); + let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); + let value = unsafe { - LLVMBuildInvoke( + LLVMBuildInvoke2( self.builder, + fn_ty_ref, fn_val_ref, args.as_mut_ptr(), args.len() as u32, @@ -822,7 +934,13 @@ impl<'ctx> Builder<'ctx> { /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 2, "struct_gep").is_err()); /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_struct_gep_2>(&self, ty: T, ptr: PointerValue<'ctx>, index: u32, name: &str) -> Result, ()> { + pub fn build_struct_gep_2>( + &self, + ty: T, + ptr: PointerValue<'ctx>, + index: u32, + name: &str, + ) -> Result, ()> { let ptr_ty = ptr.get_type(); let pointee_ty = ptr_ty.get_element_type(); @@ -884,7 +1002,7 @@ impl<'ctx> Builder<'ctx> { name: &str, ) -> IntValue<'ctx> { let c_string = to_c_str(name); - let value = unsafe { + let value = unsafe { LLVMBuildPtrDiff( self.builder, lhs_ptr.as_value_ref(), diff --git a/src/values/ptr_value.rs b/src/values/ptr_value.rs index fd0a8950236..eb177ec8a43 100644 --- a/src/values/ptr_value.rs +++ b/src/values/ptr_value.rs @@ -10,7 +10,7 @@ use std::convert::TryFrom; use std::ffi::CStr; use std::fmt::{self, Display}; -use crate::types::{AsTypeRef, IntType, PointerType, BasicType}; +use crate::types::{AsTypeRef, BasicType, IntType, PointerType}; use crate::values::{AsValueRef, InstructionValue, IntValue, Value}; use super::AnyValue; @@ -95,7 +95,11 @@ 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.0..=latest)] - pub unsafe fn const_gep_2>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { + pub unsafe fn const_gep_2>( + self, + ty: T, + ordered_indexes: &[IntValue<'ctx>], + ) -> PointerValue<'ctx> { let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); let value = { @@ -128,7 +132,11 @@ 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.0..=latest)] - pub unsafe fn const_in_bounds_gep_2>(self, ty: T, ordered_indexes: &[IntValue<'ctx>]) -> PointerValue<'ctx> { + pub unsafe fn const_in_bounds_gep_2>( + self, + ty: T, + ordered_indexes: &[IntValue<'ctx>], + ) -> PointerValue<'ctx> { let mut index_values: Vec = ordered_indexes.iter().map(|val| val.as_value_ref()).collect(); let value = { From eb770415d2cc405661e0b18a52ca9d02bffb1c5f Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 24 Nov 2022 13:38:53 +0200 Subject: [PATCH 11/34] Fix tests for passes and debug info --- src/context.rs | 1 + tests/all/test_debug_info.rs | 138 ++++++++++++++++++++--------------- tests/all/test_passes.rs | 20 ++--- 3 files changed, 90 insertions(+), 69 deletions(-) diff --git a/src/context.rs b/src/context.rs index ed2bf558dc8..beebfc9f4a4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1211,6 +1211,7 @@ impl Context { self.context.const_string(string, null_terminated) } + #[allow(dead_code)] #[inline] pub(crate) fn set_diagnostic_handler( &self, diff --git a/tests/all/test_debug_info.rs b/tests/all/test_debug_info.rs index d6d1ae8e653..a60ed3c0c62 100644 --- a/tests/all/test_debug_info.rs +++ b/tests/all/test_debug_info.rs @@ -29,14 +29,16 @@ fn test_smoke() { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -107,14 +109,16 @@ fn test_struct_with_placeholders() { feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( feature = "llvm11-0", feature = "llvm12-0", feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -228,17 +232,19 @@ fn test_no_explicit_finalize() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -269,17 +275,19 @@ fn test_replacing_placeholder_with_placeholder() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -324,17 +332,19 @@ fn test_anonymous_basic_type() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -372,17 +382,19 @@ fn test_global_expressions() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -438,17 +450,19 @@ fn test_pointer_types() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -488,17 +502,19 @@ fn test_reference_types() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -538,17 +554,19 @@ fn test_array_type() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); diff --git a/tests/all/test_passes.rs b/tests/all/test_passes.rs index 78a4d4320a3..2a9a9ec7f69 100644 --- a/tests/all/test_passes.rs +++ b/tests/all/test_passes.rs @@ -13,6 +13,7 @@ fn test_init_all_passes_for_module() { let module = context.create_module("my_module"); let pass_manager = PassManager::create(()); + #[cfg(not(feature = "llvm15-0"))] pass_manager.add_argument_promotion_pass(); pass_manager.add_constant_merge_pass(); #[cfg(not(any( @@ -30,7 +31,7 @@ fn test_init_all_passes_for_module() { pass_manager.add_always_inliner_pass(); pass_manager.add_global_dce_pass(); pass_manager.add_global_optimizer_pass(); - #[cfg(not(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0")))] + #[cfg(not(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0")))] pass_manager.add_ip_constant_propagation_pass(); pass_manager.add_prune_eh_pass(); pass_manager.add_ipsccp_pass(); @@ -58,6 +59,7 @@ fn test_init_all_passes_for_module() { pass_manager.add_loop_rotate_pass(); pass_manager.add_loop_reroll_pass(); pass_manager.add_loop_unroll_pass(); + #[cfg(not(feature = "llvm15-0"))] pass_manager.add_loop_unswitch_pass(); pass_manager.add_memcpy_optimize_pass(); pass_manager.add_partially_inline_lib_calls_pass(); @@ -70,9 +72,9 @@ fn test_init_all_passes_for_module() { pass_manager.add_scalar_repl_aggregates_pass_with_threshold(1); pass_manager.add_simplify_lib_calls_pass(); pass_manager.add_tail_call_elimination_pass(); - #[cfg(not(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0")))] + #[cfg(not(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0")))] pass_manager.add_constant_propagation_pass(); - #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0"))] + #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] pass_manager.add_instruction_simplify_pass(); pass_manager.add_demote_memory_to_register_pass(); pass_manager.add_verifier_pass(); @@ -91,7 +93,7 @@ fn test_init_all_passes_for_module() { pass_manager.add_loop_unroll_and_jam_pass(); } - #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm7-0")))] + #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0", feature = "llvm7-0", feature = "llvm15-0")))] { pass_manager.add_coroutine_early_pass(); pass_manager.add_coroutine_split_pass(); @@ -149,11 +151,11 @@ fn test_pass_manager_builder() { #[cfg(not(any(feature = "llvm4-0", feature = "llvm5-0")))] assert!(module_pass_manager.run_on(&module)); - let lto_pass_manager = PassManager::create(()); - - pass_manager_builder.populate_lto_pass_manager(<o_pass_manager, false, false); - - assert!(lto_pass_manager.run_on(&module2)); + #[cfg(not(feature = "llvm15-0"))] { + let lto_pass_manager = PassManager::create(()); + pass_manager_builder.populate_lto_pass_manager(<o_pass_manager, false, false); + assert!(lto_pass_manager.run_on(&module2)); + } } #[test] From 4330a51203104f2254960f1c40e214d788172507 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 24 Nov 2022 14:51:00 +0200 Subject: [PATCH 12/34] Update the tests --- src/basic_block.rs | 16 ++- src/builder.rs | 65 +++++++++-- tests/all/test_attributes.rs | 5 +- tests/all/test_builder.rs | 94 +++++++++++++-- tests/all/test_debug_info.rs | 142 +++++++++++------------ tests/all/test_instruction_conversion.rs | 2 +- tests/all/test_instruction_values.rs | 6 + tests/all/test_passes.rs | 37 ++++-- tests/all/test_values.rs | 124 +++++++++++--------- 9 files changed, 331 insertions(+), 160 deletions(-) diff --git a/src/basic_block.rs b/src/basic_block.rs index ff302063dd7..8e75e672243 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, LLVMSetValueName, LLVMTypeOf, + LLVMRemoveBasicBlockFromParent, LLVMReplaceAllUsesWith, LLVMTypeOf, }; use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef}; @@ -424,7 +424,19 @@ impl<'ctx> BasicBlock<'ctx> { /// Set name of the `BasicBlock`. pub fn set_name(&self, name: &str) { let c_string = to_c_str(name); - unsafe { LLVMSetValueName(LLVMBasicBlockAsValue(self.basic_block), c_string.as_ptr()) }; + + #[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(), name.len()) }; + } } /// Replaces all uses of this basic block with another. diff --git a/src/builder.rs b/src/builder.rs index c53f4c12187..c347a627c09 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2748,15 +2748,36 @@ impl<'ctx> Builder<'ctx> { } /// Set the debug info source location of the instruction currently pointed at by the builder - #[llvm_versions(7.0..=latest)] pub fn set_current_debug_location(&self, context: &'ctx crate::context::Context, location: DILocation<'ctx>) { - use llvm_sys::core::LLVMMetadataAsValue; - use llvm_sys::core::LLVMSetCurrentDebugLocation; - unsafe { - LLVMSetCurrentDebugLocation( - self.builder, - LLVMMetadataAsValue(context.context.0, location.metadata_ref), - ); + #[cfg(any( + feature = "llvm4-0", + feature = "llvm5-0", + feature = "llvm6-0", + feature = "llvm7-0", + feature = "llvm8-0" + ))] + { + use llvm_sys::core::LLVMMetadataAsValue; + use llvm_sys::core::LLVMSetCurrentDebugLocation; + unsafe { + LLVMSetCurrentDebugLocation( + self.builder, + LLVMMetadataAsValue(context.context.0, location.metadata_ref), + ); + } + } + #[cfg(not(any( + feature = "llvm4-0", + feature = "llvm5-0", + feature = "llvm6-0", + feature = "llvm7-0", + feature = "llvm8-0" + )))] + { + use llvm_sys::core::LLVMSetCurrentDebugLocation2; + unsafe { + LLVMSetCurrentDebugLocation2(self.builder, location.metadata_ref); + } } } @@ -2779,9 +2800,31 @@ 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. pub fn unset_current_debug_location(&self) { - use llvm_sys::core::LLVMSetCurrentDebugLocation; - unsafe { - LLVMSetCurrentDebugLocation(self.builder, std::ptr::null_mut()); + #[cfg(any( + feature = "llvm4-0", + feature = "llvm5-0", + feature = "llvm6-0", + feature = "llvm7-0", + feature = "llvm8-0" + ))] + { + use llvm_sys::core::LLVMSetCurrentDebugLocation; + unsafe { + LLVMSetCurrentDebugLocation(self.builder, std::ptr::null_mut()); + } + } + #[cfg(not(any( + feature = "llvm4-0", + feature = "llvm5-0", + feature = "llvm6-0", + feature = "llvm7-0", + feature = "llvm8-0" + )))] + { + use llvm_sys::core::LLVMSetCurrentDebugLocation2; + unsafe { + LLVMSetCurrentDebugLocation2(self.builder, std::ptr::null_mut()); + } } } } diff --git a/tests/all/test_attributes.rs b/tests/all/test_attributes.rs index f936362bf3d..52e71ba56b3 100644 --- a/tests/all/test_attributes.rs +++ b/tests/all/test_attributes.rs @@ -54,7 +54,7 @@ fn test_type_attribute() { context.i32_type().vec_type(1).as_any_type_enum(), context.i32_type().array_type(1).as_any_type_enum(), context.i32_type().fn_type(&[], false).as_any_type_enum(), - context.i32_type().ptr_type(AddressSpace::Local).as_any_type_enum(), + context.i32_type().ptr_type(AddressSpace::Four).as_any_type_enum(), context .struct_type(&[context.i32_type().as_basic_type_enum()], false) .as_any_type_enum(), @@ -151,7 +151,10 @@ fn test_attributes_on_call_site_values() { builder.position_at_end(entry_bb); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let call_site_value = builder.build_call(fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let call_site_value = builder.build_call_2(fn_type, fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); builder.build_return(None); diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs index 13c8971a05d..5fe49eebb6b 100644 --- a/tests/all/test_builder.rs +++ b/tests/all/test_builder.rs @@ -1,5 +1,4 @@ use inkwell::context::Context; -use inkwell::values::BasicValue; use inkwell::values::CallableValue; use inkwell::{AddressSpace, AtomicOrdering, AtomicRMWBinOp, OptimizationLevel}; @@ -29,7 +28,10 @@ fn test_build_call() { builder.position_at_end(basic_block2); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let pi2_call_site = builder.build_call(function, &[], "get_pi"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let pi2_call_site = builder.build_call_2(fn_type, function, &[], "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -57,10 +59,16 @@ fn test_build_call() { builder.build_store(alloca, fn_ptr); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let load = builder.build_load(alloca, "load").into_pointer_value(); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let load = builder.build_load_2(fn_ptr_type, alloca, "load").into_pointer_value(); let callable_value = CallableValue::try_from(load).unwrap(); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] builder.build_call(callable_value, &[], "call"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + builder.build_call_2(fn_type2, callable_value, &[], "call"); builder.build_return(None); assert!(module.verify().is_ok()); @@ -93,7 +101,10 @@ fn test_build_invoke_cleanup_resume() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!call_site.is_tail_call()); @@ -120,7 +131,7 @@ fn test_build_invoke_cleanup_resume() { }; // type of an exception in C++ - let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); let i32_type = context.i32_type(); let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); @@ -160,7 +171,10 @@ fn test_build_invoke_catch_all() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let pi2_call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -187,7 +201,7 @@ fn test_build_invoke_catch_all() { }; // type of an exception in C++ - let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); let i32_type = context.i32_type(); let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); @@ -231,7 +245,10 @@ fn landing_pad_filter() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let pi2_call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -258,12 +275,12 @@ fn landing_pad_filter() { }; // type of an exception in C++ - let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); let i32_type = context.i32_type(); let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); // link in the C++ type info for the i32 type - let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Generic), "_ZTIi"); + let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Zero), "_ZTIi"); type_info_int.set_linkage(Linkage::External); // make the filter landing pad @@ -331,7 +348,10 @@ fn test_null_checked_ptr_ops() { let ptr_as_int = builder.build_ptr_to_int(ptr, i64_type, "ptr_as_int"); let new_ptr_as_int = builder.build_int_add(ptr_as_int, one, "add"); let new_ptr = builder.build_int_to_ptr(new_ptr_as_int, i8_ptr_type, "int_as_ptr"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let index1 = builder.build_load(new_ptr, "deref"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let index1 = builder.build_load_2(i8_ptr_type, new_ptr, "deref"); builder.build_return(Some(&index1)); @@ -368,7 +388,10 @@ fn test_null_checked_ptr_ops() { let ptr_as_int = builder.build_ptr_to_int(ptr, i64_type, "ptr_as_int"); let new_ptr_as_int = builder.build_int_add(ptr_as_int, one, "add"); let new_ptr = builder.build_int_to_ptr(new_ptr_as_int, i8_ptr_type, "int_as_ptr"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let index1 = builder.build_load(new_ptr, "deref"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let index1 = builder.build_load_2(i8_ptr_type, new_ptr, "deref"); builder.build_return(Some(&index1)); @@ -876,7 +899,12 @@ fn test_insert_value() { builder.position_at_end(entry); let array_alloca = builder.build_alloca(array_type, "array_alloca"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let array = builder.build_load(array_alloca, "array_load").into_array_value(); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let array = builder + .build_load_2(array_type, array_alloca, "array_load") + .into_array_value(); let const_int1 = i32_type.const_int(2, false); let const_int2 = i32_type.const_int(5, false); let const_int3 = i32_type.const_int(6, false); @@ -903,7 +931,12 @@ fn test_insert_value() { assert!(builder.build_extract_value(array, 3, "extract").is_none()); let struct_alloca = builder.build_alloca(struct_type, "struct_alloca"); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let struct_value = builder.build_load(struct_alloca, "struct_load").into_struct_value(); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let struct_value = builder + .build_load_2(struct_type, struct_alloca, "struct_load") + .into_struct_value(); assert!(builder .build_insert_value(struct_value, const_int2, 0, "insert") @@ -998,12 +1031,16 @@ fn run_memcpy_on<'ctx>( builder.position_at_end(entry); let len_value = i64_type.const_int(array_len as u64, false); + let array_type = i32_type.array_type(array_len as u32); 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let elem_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); builder.build_store(elem_ptr, int_val); @@ -1014,7 +1051,10 @@ 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let dest_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; builder.build_memcpy(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1068,12 +1108,16 @@ fn run_memmove_on<'ctx>( builder.position_at_end(entry); let len_value = i64_type.const_int(array_len as u64, false); + let array_type = i32_type.array_type(array_len as u32); 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let elem_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); builder.build_store(elem_ptr, int_val); @@ -1084,7 +1128,10 @@ 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let dest_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; builder.build_memmove(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1131,7 +1178,7 @@ fn run_memset_on<'ctx>( let i32_type = context.i32_type(); let i64_type = context.i64_type(); let array_len = 4; - let fn_type = i32_type.ptr_type(AddressSpace::Generic).fn_type(&[], false); + let fn_type = i32_type.ptr_type(AddressSpace::Zero).fn_type(&[], false); let fn_value = module.add_function("test_fn", fn_type, None); let builder = context.create_builder(); let entry = context.append_basic_block(fn_value, "entry"); @@ -1139,6 +1186,7 @@ fn run_memset_on<'ctx>( builder.position_at_end(entry); let len_value = i64_type.const_int(array_len as u64, false); + let array_type = i32_type.array_type(array_len as u32); let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap(); let elems_to_copy = 2; @@ -1150,7 +1198,10 @@ 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let part_2 = unsafe { builder.build_in_bounds_gep(array_ptr, &[index], "index") }; + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let part_2 = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index], "index") }; builder.build_memset(part_2, alignment, val, size_val)?; builder.build_return(Some(&array_ptr)); @@ -1187,6 +1238,8 @@ fn test_memset() { #[test] fn test_bitcast() { + use inkwell::values::AnyValue; + let context = Context::create(); let module = context.create_module("bc"); let void_type = context.void_type(); @@ -1226,7 +1279,7 @@ fn test_bitcast() { assert!(module.verify().is_ok(), "{}", module.print_to_string().to_string()); - let first_iv = cast.as_instruction_value().unwrap(); + let first_iv = cast.as_any_value_enum().into_instruction_value(); builder.position_before(&first_iv); builder.build_bitcast(f64_arg, i64_type, "f64toi64"); @@ -1442,9 +1495,26 @@ 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(); - assert!(builder.build_struct_gep(i32_ptr, 0, "struct_gep").is_err()); - assert!(builder.build_struct_gep(i32_ptr, 10, "struct_gep").is_err()); - assert!(builder.build_struct_gep(struct_ptr, 0, "struct_gep").is_ok()); - 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + { + assert!(builder.build_struct_gep(i32_ptr, 0, "struct_gep").is_err()); + assert!(builder.build_struct_gep(i32_ptr, 10, "struct_gep").is_err()); + assert!(builder.build_struct_gep(struct_ptr, 0, "struct_gep").is_ok()); + 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 = "llvm14-0", feature = "llvm15-0"))] + { + assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 0, "struct_gep").is_err()); + assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 10, "struct_gep").is_err()); + assert!(builder + .build_struct_gep_2(struct_ty, struct_ptr, 0, "struct_gep") + .is_ok()); + assert!(builder + .build_struct_gep_2(struct_ty, struct_ptr, 1, "struct_gep") + .is_ok()); + assert!(builder + .build_struct_gep_2(struct_ty, struct_ptr, 2, "struct_gep") + .is_err()); + } } diff --git a/tests/all/test_debug_info.rs b/tests/all/test_debug_info.rs index a60ed3c0c62..913086c1459 100644 --- a/tests/all/test_debug_info.rs +++ b/tests/all/test_debug_info.rs @@ -232,19 +232,19 @@ fn test_no_explicit_finalize() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -275,19 +275,19 @@ fn test_replacing_placeholder_with_placeholder() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -332,19 +332,19 @@ fn test_anonymous_basic_type() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -382,19 +382,19 @@ fn test_global_expressions() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -450,19 +450,19 @@ fn test_pointer_types() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -479,7 +479,7 @@ fn test_pointer_types() { .as_type(); //Smoke test that the pointer gets created - dibuilder.create_pointer_type("pointer_name", di_type, 64, 64, inkwell::AddressSpace::Global); + dibuilder.create_pointer_type("pointer_name", di_type, 64, 64, inkwell::AddressSpace::One); } #[test] @@ -502,19 +502,19 @@ fn test_reference_types() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); @@ -554,19 +554,19 @@ fn test_array_type() { false, false, #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", #[cfg(any( - feature = "llvm11-0", - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" + feature = "llvm11-0", + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" ))] "", ); diff --git a/tests/all/test_instruction_conversion.rs b/tests/all/test_instruction_conversion.rs index 6dc11a9803d..9539dd2953f 100644 --- a/tests/all/test_instruction_conversion.rs +++ b/tests/all/test_instruction_conversion.rs @@ -109,7 +109,7 @@ fn test_conversion_to_pointer_value() { // Create a PointerType instruction let i64_type = context.i64_type(); - let i64_ptr_type = i64_type.ptr_type(AddressSpace::Generic); + let i64_ptr_type = i64_type.ptr_type(AddressSpace::Zero); let alloca_instr = builder.build_alloca(i64_ptr_type, "alloca").as_instruction().unwrap(); // Test the instruction conversion to a FloatValue diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index 2a33d4dd126..2f290cacd3a 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -416,7 +416,10 @@ fn test_mem_instructions() { let f32_val = f32_type.const_float(::std::f64::consts::PI); let store_instruction = builder.build_store(arg1, f32_val); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let load = builder.build_load(arg1, ""); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let load = builder.build_load_2(f32_ptr_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); assert_eq!(store_instruction.get_volatile().unwrap(), false); @@ -479,7 +482,10 @@ 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); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let load = builder.build_load(arg1, ""); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let load = builder.build_load_2(f32_ptr_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); assert_eq!( diff --git a/tests/all/test_passes.rs b/tests/all/test_passes.rs index 2a9a9ec7f69..bad66ef3a04 100644 --- a/tests/all/test_passes.rs +++ b/tests/all/test_passes.rs @@ -31,7 +31,12 @@ fn test_init_all_passes_for_module() { pass_manager.add_always_inliner_pass(); pass_manager.add_global_dce_pass(); pass_manager.add_global_optimizer_pass(); - #[cfg(not(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(any( + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" + )))] pass_manager.add_ip_constant_propagation_pass(); pass_manager.add_prune_eh_pass(); pass_manager.add_ipsccp_pass(); @@ -72,9 +77,19 @@ fn test_init_all_passes_for_module() { pass_manager.add_scalar_repl_aggregates_pass_with_threshold(1); pass_manager.add_simplify_lib_calls_pass(); pass_manager.add_tail_call_elimination_pass(); - #[cfg(not(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(any( + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" + )))] pass_manager.add_constant_propagation_pass(); - #[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(any( + feature = "llvm12-0", + feature = "llvm13-0", + feature = "llvm14-0", + feature = "llvm15-0" + ))] pass_manager.add_instruction_simplify_pass(); pass_manager.add_demote_memory_to_register_pass(); pass_manager.add_verifier_pass(); @@ -93,7 +108,13 @@ fn test_init_all_passes_for_module() { 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")))] + #[cfg(not(any( + feature = "llvm4-0", + feature = "llvm5-0", + feature = "llvm6-0", + feature = "llvm7-0", + feature = "llvm15-0" + )))] { pass_manager.add_coroutine_early_pass(); pass_manager.add_coroutine_split_pass(); @@ -144,16 +165,18 @@ fn test_pass_manager_builder() { pass_manager_builder.populate_module_pass_manager(&module_pass_manager); - let module2 = module.clone(); - #[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)); - #[cfg(not(feature = "llvm15-0"))] { + #[cfg(not(feature = "llvm15-0"))] + { + let module2 = module.clone(); + let lto_pass_manager = PassManager::create(()); pass_manager_builder.populate_lto_pass_manager(<o_pass_manager, false, false); + assert!(lto_pass_manager.run_on(&module2)); } } diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index d6796a46342..2fd29e0810e 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -5,7 +5,7 @@ use inkwell::context::Context; use inkwell::module::Linkage::*; use inkwell::types::{StringRadix, VectorType}; use inkwell::values::{AnyValue, CallableValue, InstructionOpcode::*, FIRST_CUSTOM_METADATA_KIND_ID}; -use inkwell::{AddressSpace, DLLStorageClass, FloatPredicate, GlobalVisibility, ThreadLocalMode}; +use inkwell::{AddressSpace, DLLStorageClass, GlobalVisibility, ThreadLocalMode}; use std::convert::TryFrom; @@ -39,7 +39,10 @@ fn test_call_site() { let function = module.add_function("do_nothing", fn_type, None); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let call_site = builder.build_call(function, &[], "to_infinity_and_beyond"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + let call_site = builder.build_call_2(fn_type, function, &[], "to_infinity_and_beyond"); assert_eq!(call_site.count_arguments(), 0); assert!(!call_site.is_tail_call()); @@ -419,7 +422,7 @@ fn test_metadata() { // 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); - // let ptr_val = bool_type.ptr_type(AddressSpace::Generic).const_null(); + // let ptr_val = bool_type.ptr_type(AddressSpace::Zero).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]); @@ -522,77 +525,82 @@ fn test_metadata() { #[test] fn test_floats() { - let context = Context::create(); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + { + use inkwell::FloatPredicate; - let f32_type = context.f32_type(); - let f64_type = context.f64_type(); - let f128_type = context.f128_type(); - let i64_type = context.i32_type(); + let context = Context::create(); + + let f32_type = context.f32_type(); + let f64_type = context.f64_type(); + let f128_type = context.f128_type(); + let i64_type = context.i32_type(); - let f64_pi = f64_type.const_float(::std::f64::consts::PI); + let f64_pi = f64_type.const_float(::std::f64::consts::PI); - let f32_pi = f64_pi.const_truncate(f32_type); - let f128_pi = f64_pi.const_extend(f128_type); - let i64_pi = f64_pi.const_to_signed_int(i64_type); - let u64_pi = f64_pi.const_to_unsigned_int(i64_type); - let f128_pi_cast = f64_pi.const_cast(f128_type); + let f32_pi = f64_pi.const_truncate(f32_type); + let f128_pi = f64_pi.const_extend(f128_type); + let i64_pi = f64_pi.const_to_signed_int(i64_type); + let u64_pi = f64_pi.const_to_unsigned_int(i64_type); + let f128_pi_cast = f64_pi.const_cast(f128_type); - assert_eq!(i64_pi.get_type(), i64_type); - assert_eq!(u64_pi.get_type(), i64_type); - assert_eq!(f32_pi.get_type(), f32_type); - assert_eq!(f128_pi.get_type(), f128_type); - assert_eq!(f128_pi_cast.get_type(), f128_type); + assert_eq!(i64_pi.get_type(), i64_type); + assert_eq!(u64_pi.get_type(), i64_type); + assert_eq!(f32_pi.get_type(), f32_type); + 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? - // 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()); - assert!(i64_pi.as_instruction().is_none()); - assert!(u64_pi.as_instruction().is_none()); - assert!(f128_pi_cast.as_instruction().is_none()); + // REIVEW: 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()); + assert!(i64_pi.as_instruction().is_none()); + assert!(u64_pi.as_instruction().is_none()); + assert!(f128_pi_cast.as_instruction().is_none()); - let f64_one = f64_type.const_float(1.); - let f64_two = f64_type.const_float(2.); - let neg_two = f64_two.const_neg(); + let f64_one = f64_type.const_float(1.); + let f64_two = f64_type.const_float(2.); + let neg_two = f64_two.const_neg(); - assert_eq!(neg_two.print_to_string().to_str(), Ok("double -2.000000e+00")); + assert_eq!(neg_two.print_to_string().to_str(), Ok("double -2.000000e+00")); - let neg_three = neg_two.const_sub(f64_one); + let neg_three = neg_two.const_sub(f64_one); - assert_eq!(neg_three.print_to_string().to_str(), Ok("double -3.000000e+00")); + assert_eq!(neg_three.print_to_string().to_str(), Ok("double -3.000000e+00")); - let pos_six = neg_three.const_mul(neg_two); + let pos_six = neg_three.const_mul(neg_two); - assert_eq!(pos_six.print_to_string().to_str(), Ok("double 6.000000e+00")); + assert_eq!(pos_six.print_to_string().to_str(), Ok("double 6.000000e+00")); - let pos_eight = pos_six.const_add(f64_two); + let pos_eight = pos_six.const_add(f64_two); - assert_eq!(pos_eight.print_to_string().to_str(), Ok("double 8.000000e+00")); + assert_eq!(pos_eight.print_to_string().to_str(), Ok("double 8.000000e+00")); - let pos_four = pos_eight.const_div(f64_two); + let pos_four = pos_eight.const_div(f64_two); - assert_eq!(pos_four.print_to_string().to_str(), Ok("double 4.000000e+00")); + assert_eq!(pos_four.print_to_string().to_str(), Ok("double 4.000000e+00")); - let rem = pos_six.const_remainder(pos_four); + let rem = pos_six.const_remainder(pos_four); - assert_eq!(rem.print_to_string().to_str(), Ok("double 2.000000e+00")); + assert_eq!(rem.print_to_string().to_str(), Ok("double 2.000000e+00")); - assert!(f64_one.const_compare(FloatPredicate::PredicateFalse, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::PredicateTrue, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::OEQ, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::OGT, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::OGE, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::OLT, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::OLE, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::ONE, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::UEQ, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::UGT, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::UGE, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::ULT, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::ULE, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::UNE, f64_two).is_null()); - assert!(!f64_one.const_compare(FloatPredicate::ORD, f64_two).is_null()); - assert!(f64_one.const_compare(FloatPredicate::UNO, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::PredicateFalse, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::PredicateTrue, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::OEQ, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::OGT, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::OGE, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::OLT, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::OLE, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::ONE, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::UEQ, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::UGT, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::UGE, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::ULT, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::ULE, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::UNE, f64_two).is_null()); + assert!(!f64_one.const_compare(FloatPredicate::ORD, f64_two).is_null()); + assert!(f64_one.const_compare(FloatPredicate::UNO, f64_two).is_null()); + } } #[test] @@ -1142,7 +1150,10 @@ fn test_non_fn_ptr_called() { builder.position_at_end(bb); let callable_value = CallableValue::try_from(i8_ptr_param).unwrap(); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] builder.build_call(callable_value, &[], "call"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + builder.build_call_2(i8_ptr_type.fn_type(&[], false), callable_value, &[], "call"); builder.build_return(None); assert!(module.verify().is_ok()); @@ -1189,7 +1200,10 @@ fn test_aggregate_returns() { let ptr_param2 = fn_value.get_nth_param(1).unwrap().into_pointer_value(); builder.position_at_end(bb); + #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] builder.build_ptr_diff(ptr_param1, ptr_param2, "diff"); + #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + builder.build_ptr_diff_2(i32_ptr_type, ptr_param1, ptr_param2, "diff"); builder.build_aggregate_return(&[i32_three.into(), i32_seven.into()]); assert!(module.verify().is_ok()); From abeb758e3e232ae2bcca5fd9816c2e3bc63ff4e1 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 24 Nov 2022 15:11:38 +0200 Subject: [PATCH 13/34] Remove the local target artifacts --- Cargo.toml | 1 - src/targets.rs | 39 --------------------------------------- 2 files changed, 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc47a5d21f4..2354460f03a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,6 @@ target-all = [ "target-lanai", "target-webassembly", "target-riscv", - "target-syncvm", ] experimental = ["static-alloc"] nightly = ["inkwell_internals/nightly"] diff --git a/src/targets.rs b/src/targets.rs index 1c691f60fed..f3da0632b07 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -752,45 +752,6 @@ impl Target { } } - #[cfg(feature = "target-syncvm")] - #[llvm_versions(11.0..=latest)] - pub fn initialize_syncvm(config: &InitializationConfig) { - use llvm_sys::target::{ - LLVMInitializeSyncVMAsmParser, LLVMInitializeSyncVMAsmPrinter, LLVMInitializeSyncVMDisassembler, - LLVMInitializeSyncVMTarget, LLVMInitializeSyncVMTargetInfo, LLVMInitializeSyncVMTargetMC, - }; - - if config.base { - let _guard = TARGET_LOCK.write(); - unsafe { LLVMInitializeSyncVMTarget() }; - } - - if config.info { - let _guard = TARGET_LOCK.write(); - unsafe { LLVMInitializeSyncVMTargetInfo() }; - } - - if config.asm_printer { - let _guard = TARGET_LOCK.write(); - unsafe { LLVMInitializeSyncVMAsmPrinter() }; - } - - if config.asm_parser { - let _guard = TARGET_LOCK.write(); - unsafe { LLVMInitializeSyncVMAsmParser() }; - } - - if config.disassembler { - let _guard = TARGET_LOCK.write(); - unsafe { LLVMInitializeSyncVMDisassembler() }; - } - - if config.machine_code { - let _guard = TARGET_LOCK.write(); - unsafe { LLVMInitializeSyncVMTargetMC() }; - } - } - pub fn initialize_native(config: &InitializationConfig) -> Result<(), String> { use llvm_sys::target::{ LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeDisassembler, From dee5b784e67d8adc7b83b697a2eaef05562a60d4 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 24 Nov 2022 15:36:50 +0200 Subject: [PATCH 14/34] Restore the deprecated passes and const functions --- src/builder.rs | 2 - src/context.rs | 6 +- src/lib.rs | 4 +- src/module.rs | 65 ---------------------- src/passes.rs | 112 ++++++++++++++++++++++++++++++++++++++ src/values/float_value.rs | 35 ++++++++++++ src/values/int_value.rs | 42 ++++++++++++++ src/values/traits.rs | 31 +++++++++++ 8 files changed, 225 insertions(+), 72 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 45d7212cbf1..c347a627c09 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -36,8 +36,6 @@ use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef}; use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] -use crate::context::AsContextRef; -#[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; use crate::support::to_c_str; use crate::types::{ diff --git a/src/context.rs b/src/context.rs index 1689fb40cec..97d54b9d3df 100644 --- a/src/context.rs +++ b/src/context.rs @@ -19,9 +19,9 @@ use llvm_sys::core::{ LLVMAppendBasicBlockInContext, LLVMConstStringInContext, LLVMConstStructInContext, LLVMContextCreate, LLVMContextDispose, LLVMContextSetDiagnosticHandler, LLVMCreateBuilderInContext, LLVMCreateEnumAttribute, LLVMCreateStringAttribute, LLVMDoubleTypeInContext, LLVMFP128TypeInContext, LLVMFloatTypeInContext, - LLVMGetGlobalContext, LLVMGetMDKindIDInContext, LLVMGetTypeKind, LLVMHalfTypeInContext, - LLVMInsertBasicBlockInContext, LLVMInt16TypeInContext, LLVMInt1TypeInContext, LLVMInt32TypeInContext, - LLVMInt64TypeInContext, LLVMInt8TypeInContext, LLVMIntTypeInContext, LLVMMDNodeInContext, LLVMMDStringInContext, + LLVMGetGlobalContext, LLVMGetMDKindIDInContext, LLVMHalfTypeInContext, LLVMInsertBasicBlockInContext, + LLVMInt16TypeInContext, LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext, + LLVMInt8TypeInContext, LLVMIntTypeInContext, LLVMMDNodeInContext, LLVMMDStringInContext, LLVMModuleCreateWithNameInContext, LLVMPPCFP128TypeInContext, LLVMStructCreateNamed, LLVMStructTypeInContext, LLVMVoidTypeInContext, LLVMX86FP80TypeInContext, }; diff --git a/src/lib.rs b/src/lib.rs index 0ff4639b1b2..c9a21dfce46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,12 +331,12 @@ pub enum AtomicRMWBinOp { #[llvm_variant(LLVMAtomicRMWBinOpFSub)] FSub, - /// Sets memory to the float-typed-greater of the value provided and the value in memory. Returns the value that was in memory. + /// Sets memory to the greater of the two float-typed values, one provided and one from memory. Returns the value that was in memory. #[llvm_versions(15.0..=latest)] #[llvm_variant(LLVMAtomicRMWBinOpFMax)] FMax, - /// Sets memory to the float-typed-lesser of the value provided and the value in memory. Returns the value that was in memory. + /// Sets memory to the lesser of the two float-typed values, one provided and one from memory. Returns the value that was in memory. #[llvm_versions(15.0..=latest)] #[llvm_variant(LLVMAtomicRMWBinOpFMin)] FMin, diff --git a/src/module.rs b/src/module.rs index 58ba9e8fc4e..64b406a7cb0 100644 --- a/src/module.rs +++ b/src/module.rs @@ -7,7 +7,6 @@ use llvm_sys::bit_writer::{LLVMWriteBitcodeToFile, LLVMWriteBitcodeToMemoryBuffe #[llvm_versions(4.0..14.0)] use llvm_sys::core::LLVMGetTypeByName; - use llvm_sys::core::{ LLVMAddFunction, LLVMAddGlobal, LLVMAddGlobalInAddressSpace, LLVMAddNamedMetadataOperand, LLVMCloneModule, LLVMDisposeModule, LLVMDumpModule, LLVMGetFirstFunction, LLVMGetFirstGlobal, LLVMGetLastFunction, @@ -22,7 +21,6 @@ use llvm_sys::error::LLVMGetErrorMessage; use llvm_sys::execution_engine::{ LLVMCreateExecutionEngineForModule, LLVMCreateInterpreterForModule, LLVMCreateJITCompilerForModule, }; -use llvm_sys::ir_reader::LLVMParseIRInContext; use llvm_sys::prelude::{LLVMModuleRef, LLVMValueRef}; #[llvm_versions(13.0..=latest)] use llvm_sys::transforms::pass_builder::LLVMRunPasses; @@ -1099,69 +1097,6 @@ impl<'ctx> Module<'ctx> { unsafe { Some(GlobalValue::new(value)) } } - /// Creates a new `Module` from a `MemoryBuffer` with IR. - /// - /// # Example - /// - /// ```no_run - /// use inkwell::context::Context; - /// use inkwell::module::Module; - /// use inkwell::memory_buffer::MemoryBuffer; - /// use std::path::Path; - /// - /// let path = Path::new("foo/bar.ll"); - /// let context = Context::create(); - /// let buffer = MemoryBuffer::create_from_file(&path).unwrap(); - /// let module = Module::parse_ir_from_buffer(&buffer, &context); - /// - /// assert_eq!(*module.unwrap().get_context(), context); - /// - /// ``` - pub fn parse_ir_from_buffer(buffer: &MemoryBuffer, context: &'ctx Context) -> Result { - let mut module = MaybeUninit::uninit(); - let mut err_string = MaybeUninit::uninit(); - - let success = unsafe { - LLVMParseIRInContext( - context.context.0, - buffer.memory_buffer, - module.as_mut_ptr(), - err_string.as_mut_ptr(), - ) - }; - - if success != 0 { - let err_string = unsafe { err_string.assume_init() }; - return Err(unsafe { LLVMString::new(err_string) }); - } - - let module = unsafe { module.assume_init() }; - - Ok(unsafe { Module::new(module) }) - } - - /// A convenience function for creating a `Module` from an IR file for a given context. - /// - /// # Example - /// - /// ```no_run - /// use inkwell::context::Context; - /// use inkwell::module::Module; - /// use std::path::Path; - /// - /// let path = Path::new("foo/bar.ll"); - /// let context = Context::create(); - /// let module = Module::parse_ir_from_path(&path, &context); - /// - /// assert_eq!(*module.unwrap().get_context(), context); - /// - /// ``` - pub fn parse_ir_from_path>(path: P, context: &'ctx Context) -> Result { - let buffer = MemoryBuffer::create_from_file(path.as_ref())?; - - Self::parse_ir_from_buffer(&buffer, &context) - } - /// Creates a new `Module` from a `MemoryBuffer` with bitcode. /// /// # Example diff --git a/src/passes.rs b/src/passes.rs index 1defb0fdbf6..e51bb348a97 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -160,6 +160,38 @@ impl PassManagerBuilder { pub fn populate_module_pass_manager(&self, pass_manager: &PassManager) { unsafe { LLVMPassManagerBuilderPopulateModulePassManager(self.pass_manager_builder, pass_manager.pass_manager) } } + + /// Populates a PassManager with the expectation of link time + /// optimization transformations. + /// + /// # Example + /// + /// ```no_run + /// use inkwell::OptimizationLevel::Aggressive; + /// use inkwell::passes::{PassManager, PassManagerBuilder}; + /// use inkwell::targets::{InitializationConfig, Target}; + /// + /// let config = InitializationConfig::default(); + /// Target::initialize_native(&config).unwrap(); + /// let pass_manager_builder = PassManagerBuilder::create(); + /// + /// pass_manager_builder.set_optimization_level(Aggressive); + /// + /// let lpm = PassManager::create(()); + /// + /// pass_manager_builder.populate_lto_pass_manager(&lpm, false, false); + /// ``` + #[llvm_versions(4.0..15.0)] + pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) { + unsafe { + LLVMPassManagerBuilderPopulateLTOPassManager( + self.pass_manager_builder, + pass_manager.pass_manager, + internalize as i32, + run_inliner as i32, + ) + } + } } impl Drop for PassManagerBuilder { @@ -249,6 +281,29 @@ impl PassManager { unsafe { input.run_in_pass_manager(self) } } + /// This pass promotes "by reference" arguments to be "by value" arguments. + /// In practice, this means looking for internal functions that have pointer + /// arguments. If it can prove, through the use of alias analysis, that an + /// argument is only loaded, then it can pass the value into the function + /// instead of the address of the value. This can cause recursive simplification + /// of code and lead to the elimination of allocas (especially in C++ template + /// code like the STL). + /// + /// This pass also handles aggregate arguments that are passed into a function, + /// scalarizing them if the elements of the aggregate are only loaded. Note that + /// it refuses to scalarize aggregates which would require passing in more than + /// three operands to the function, because passing thousands of operands for a + /// large array or structure is unprofitable! + /// + /// Note that this transformation could also be done for arguments that are + /// only stored to (returning the value instead), but does not currently. + /// This case would be best handled when and if LLVM starts supporting multiple + /// return values from functions. + #[llvm_versions(4.0..15.0)] + pub fn add_argument_promotion_pass(&self) { + unsafe { LLVMAddArgumentPromotionPass(self.pass_manager) } + } + /// Merges duplicate global constants together into a single constant that is /// shared. This is useful because some passes (i.e., TraceValues) insert a lot /// of string constants into the program, regardless of whether or not an existing @@ -644,6 +699,35 @@ impl PassManager { unsafe { LLVMAddLoopUnrollPass(self.pass_manager) } } + /// This pass transforms loops that contain branches on + /// loop-invariant conditions to have multiple loops. + /// For example, it turns the left into the right code: + /// + /// ```c + /// for (...) if (lic) + /// A for (...) + /// if (lic) A; B; C + /// B else + /// C for (...) + /// A; C + /// ``` + /// + /// This can increase the size of the code exponentially + /// (doubling it every time a loop is unswitched) so we + /// only unswitch if the resultant code will be smaller + /// than a threshold. + /// + /// This pass expects [LICM](https://llvm.org/docs/Passes.html#passes-licm) + /// to be run before it to hoist invariant conditions + /// out of the loop, to make the unswitching opportunity + /// obvious. + #[llvm_versions(4.0..15.0)] + pub fn add_loop_unswitch_pass(&self) { + use llvm_sys::core::LLVMAddLoopUnswitchPass; + + unsafe { LLVMAddLoopUnswitchPass(self.pass_manager) } + } + /// This pass performs various transformations related /// to eliminating memcpy calls, or transforming sets /// of stores into memsets. @@ -926,6 +1010,34 @@ impl PassManager { unsafe { LLVMAddLoopUnrollAndJamPass(self.pass_manager) } } + + #[llvm_versions(8.0..15.0)] + pub fn add_coroutine_early_pass(&self) { + use llvm_sys::transforms::coroutines::LLVMAddCoroEarlyPass; + + unsafe { LLVMAddCoroEarlyPass(self.pass_manager) } + } + + #[llvm_versions(8.0..15.0)] + pub fn add_coroutine_split_pass(&self) { + use llvm_sys::transforms::coroutines::LLVMAddCoroSplitPass; + + unsafe { LLVMAddCoroSplitPass(self.pass_manager) } + } + + #[llvm_versions(8.0..15.0)] + pub fn add_coroutine_elide_pass(&self) { + use llvm_sys::transforms::coroutines::LLVMAddCoroElidePass; + + unsafe { LLVMAddCoroElidePass(self.pass_manager) } + } + + #[llvm_versions(8.0..15.0)] + pub fn add_coroutine_cleanup_pass(&self) { + use llvm_sys::transforms::coroutines::LLVMAddCoroCleanupPass; + + unsafe { LLVMAddCoroCleanupPass(self.pass_manager) } + } } impl Drop for PassManager { diff --git a/src/values/float_value.rs b/src/values/float_value.rs index 5881c9cdd11..627ed86f58a 100644 --- a/src/values/float_value.rs +++ b/src/values/float_value.rs @@ -64,6 +64,41 @@ impl<'ctx> FloatValue<'ctx> { unsafe { FloatValue::new(LLVMConstFNeg(self.as_value_ref())) } } + #[llvm_versions(4.0..15.0)] + pub fn const_add(self, rhs: FloatValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstFAdd; + + unsafe { FloatValue::new(LLVMConstFAdd(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_sub(self, rhs: FloatValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstFSub; + + unsafe { FloatValue::new(LLVMConstFSub(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_mul(self, rhs: FloatValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstFMul; + + unsafe { FloatValue::new(LLVMConstFMul(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_div(self, rhs: FloatValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstFDiv; + + unsafe { FloatValue::new(LLVMConstFDiv(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_remainder(self, rhs: FloatValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstFRem; + + unsafe { FloatValue::new(LLVMConstFRem(self.as_value_ref(), rhs.as_value_ref())) } + } + pub fn const_cast(self, float_type: FloatType<'ctx>) -> Self { unsafe { FloatValue::new(LLVMConstFPCast(self.as_value_ref(), float_type.as_type_ref())) } } diff --git a/src/values/int_value.rs b/src/values/int_value.rs index 4511da71e0a..c38773f1f74 100644 --- a/src/values/int_value.rs +++ b/src/values/int_value.rs @@ -117,6 +117,48 @@ impl<'ctx> IntValue<'ctx> { unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) } } + #[llvm_versions(4.0..15.0)] + pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstUDiv; + + unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstSDiv; + + unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstExactSDiv; + + unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstExactUDiv; + + unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstURem; + + unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) } + } + + #[llvm_versions(4.0..15.0)] + pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self { + use llvm_sys::core::LLVMConstSRem; + + unsafe { IntValue::new(LLVMConstSRem(self.as_value_ref(), rhs.as_value_ref())) } + } + pub fn const_and(self, rhs: IntValue<'ctx>) -> Self { unsafe { IntValue::new(LLVMConstAnd(self.as_value_ref(), rhs.as_value_ref())) } } diff --git a/src/values/traits.rs b/src/values/traits.rs index 957671fa673..bae2dde75e3 100644 --- a/src/values/traits.rs +++ b/src/values/traits.rs @@ -50,6 +50,37 @@ pub trait AggregateValue<'ctx>: BasicValue<'ctx> { fn as_aggregate_value_enum(&self) -> AggregateValueEnum<'ctx> { unsafe { AggregateValueEnum::new(self.as_value_ref()) } } + + // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option? + // or is that only in bounds GEP + // REVIEW: Should this be AggregatePointerValue? + #[llvm_versions(4.0..15.0)] + fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { + use llvm_sys::core::LLVMConstExtractValue; + + unsafe { + BasicValueEnum::new(LLVMConstExtractValue( + self.as_value_ref(), + indexes.as_mut_ptr(), + indexes.len() as u32, + )) + } + } + + // SubTypes: value should really be T in self: VectorValue I think + #[llvm_versions(4.0..15.0)] + fn const_insert_value>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { + use llvm_sys::core::LLVMConstInsertValue; + + unsafe { + BasicValueEnum::new(LLVMConstInsertValue( + self.as_value_ref(), + value.as_value_ref(), + indexes.as_mut_ptr(), + indexes.len() as u32, + )) + } + } } /// Represents a basic value, which can be used both by itself, or in an `AggregateValue`. From 5fedbd329a5340ae618148078a90d6b118b8071f Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 24 Nov 2022 21:56:41 +0200 Subject: [PATCH 15/34] Remove a function type check (cherry picked from commit 124a0884a8838301eee1ab61a1c51d959f89aba1) --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index c347a627c09..a7b454988a6 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -238,7 +238,7 @@ impl<'ctx> Builder<'ctx> { let fn_val_ref = callable_value.as_value_ref(); // LLVM gets upset when void return calls are named because they don't return anything - let name = if callable_value.returns_void() { "" } else { name }; + let name = if fn_ty.get_return_type().is_none() { "" } else { name }; let c_string = to_c_str(name); let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); From ea49435bed7735cba2ec5a51e9677006e1cf59db Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 27 Nov 2022 11:14:12 +0200 Subject: [PATCH 16/34] Remove function extensions, fix LLVM version deps --- Cargo.toml | 4 +-- src/builder.rs | 32 ++++++++++---------- src/values/ptr_value.rs | 8 ++--- tests/all/test_attributes.rs | 2 +- tests/all/test_builder.rs | 44 +++++++++++++--------------- tests/all/test_instruction_values.rs | 4 +-- tests/all/test_values.rs | 6 ++-- 7 files changed, 46 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2354460f03a..a153cda90ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,8 +97,8 @@ 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.2", optional = true } -llvm-sys-130 = { package = "llvm-sys", version = "130.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 } once_cell = "1.16" diff --git a/src/builder.rs b/src/builder.rs index a7b454988a6..d99f0b93759 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -215,7 +215,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.position_at_end(entry); /// - /// let ret_val = builder.build_call_2(fn_type, fn_value, &[i32_arg.into(), md_string.into()], "call") + /// let ret_val = builder.build_call(fn_type, fn_value, &[i32_arg.into(), md_string.into()], "call") /// .try_as_basic_value() /// .left() /// .unwrap(); @@ -223,7 +223,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&ret_val)); /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_call_2( + pub fn build_call( &self, fn_ty: FunctionType<'ctx>, function: F, @@ -417,7 +417,7 @@ impl<'ctx> Builder<'ctx> { /// let then_block = context.append_basic_block(function2, "then_block"); /// let catch_block = context.append_basic_block(function2, "catch_block"); /// - /// let call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); + /// let call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); /// /// { /// builder.position_at_end(then_block); @@ -452,7 +452,7 @@ impl<'ctx> Builder<'ctx> { /// } /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_invoke_2( + pub fn build_invoke( &self, fn_ty: FunctionType<'ctx>, function: F, @@ -770,7 +770,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.0..=latest)] - pub unsafe fn build_gep_2>( + pub unsafe fn build_gep>( &self, ty: T, ptr: PointerValue<'ctx>, @@ -822,7 +822,7 @@ impl<'ctx> Builder<'ctx> { // 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.0..=latest)] - pub unsafe fn build_in_bounds_gep_2>( + pub unsafe fn build_in_bounds_gep>( &self, ty: T, ptr: PointerValue<'ctx>, @@ -927,14 +927,14 @@ impl<'ctx> Builder<'ctx> { /// let i32_ptr = fn_value.get_first_param().unwrap().into_pointer_value(); /// let struct_ptr = fn_value.get_last_param().unwrap().into_pointer_value(); /// - /// assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 0, "struct_gep").is_err()); - /// assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 10, "struct_gep").is_err()); - /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 0, "struct_gep").is_ok()); - /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 1, "struct_gep").is_ok()); - /// assert!(builder.build_struct_gep_2(struct_ty, struct_ptr, 2, "struct_gep").is_err()); + /// 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()); + /// assert!(builder.build_struct_gep(struct_ty, struct_ptr, 0, "struct_gep").is_ok()); + /// 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(14.0..=latest)] - pub fn build_struct_gep_2>( + pub fn build_struct_gep>( &self, ty: T, ptr: PointerValue<'ctx>, @@ -1036,11 +1036,11 @@ impl<'ctx> Builder<'ctx> { /// let i32_ptr_param2 = fn_value.get_nth_param(1).unwrap().into_pointer_value(); /// /// builder.position_at_end(entry); - /// builder.build_ptr_diff_2(i32_ptr_type, i32_ptr_param1, i32_ptr_param2, "diff"); + /// builder.build_ptr_diff(i32_ptr_type, i32_ptr_param1, i32_ptr_param2, "diff"); /// builder.build_return(None); /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_ptr_diff_2>( + pub fn build_ptr_diff>( &self, ty: T, lhs_ptr: PointerValue<'ctx>, @@ -1160,12 +1160,12 @@ impl<'ctx> Builder<'ctx> { /// /// builder.position_at_end(entry); /// - /// let pointee = builder.build_load_2(i32_type, i32_ptr_param, "load2"); + /// let pointee = builder.build_load(i32_type, i32_ptr_param, "load2"); /// /// builder.build_return(Some(&pointee)); /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_load_2>(&self, ty: T, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { + pub fn build_load>(&self, ty: T, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); let value = unsafe { LLVMBuildLoad2(self.builder, ty.as_type_ref(), ptr.as_value_ref(), c_string.as_ptr()) }; diff --git a/src/values/ptr_value.rs b/src/values/ptr_value.rs index eb177ec8a43..5bf09763ad6 100644 --- a/src/values/ptr_value.rs +++ b/src/values/ptr_value.rs @@ -95,11 +95,7 @@ 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.0..=latest)] - pub unsafe fn const_gep_2>( - self, - ty: T, - ordered_indexes: &[IntValue<'ctx>], - ) -> PointerValue<'ctx> { + 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(); let value = { @@ -132,7 +128,7 @@ 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.0..=latest)] - pub unsafe fn const_in_bounds_gep_2>( + pub unsafe fn const_in_bounds_gep>( self, ty: T, ordered_indexes: &[IntValue<'ctx>], diff --git a/tests/all/test_attributes.rs b/tests/all/test_attributes.rs index 52e71ba56b3..333effc6fda 100644 --- a/tests/all/test_attributes.rs +++ b/tests/all/test_attributes.rs @@ -154,7 +154,7 @@ fn test_attributes_on_call_site_values() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let call_site_value = builder.build_call(fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let call_site_value = builder.build_call_2(fn_type, fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); + let call_site_value = builder.build_call(fn_type, fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); builder.build_return(None); diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs index 5fe49eebb6b..c00d56506c9 100644 --- a/tests/all/test_builder.rs +++ b/tests/all/test_builder.rs @@ -31,7 +31,7 @@ fn test_build_call() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let pi2_call_site = builder.build_call(function, &[], "get_pi"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let pi2_call_site = builder.build_call_2(fn_type, function, &[], "get_pi"); + let pi2_call_site = builder.build_call(fn_type, function, &[], "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -62,13 +62,13 @@ fn test_build_call() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let load = builder.build_load(alloca, "load").into_pointer_value(); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let load = builder.build_load_2(fn_ptr_type, alloca, "load").into_pointer_value(); + let load = builder.build_load(fn_ptr_type, alloca, "load").into_pointer_value(); let callable_value = CallableValue::try_from(load).unwrap(); #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] builder.build_call(callable_value, &[], "call"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - builder.build_call_2(fn_type2, callable_value, &[], "call"); + builder.build_call(fn_type2, callable_value, &[], "call"); builder.build_return(None); assert!(module.verify().is_ok()); @@ -104,7 +104,7 @@ fn test_build_invoke_cleanup_resume() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); + let call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!call_site.is_tail_call()); @@ -174,7 +174,7 @@ fn test_build_invoke_catch_all() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let pi2_call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); + let pi2_call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -248,7 +248,7 @@ fn landing_pad_filter() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let pi2_call_site = builder.build_invoke_2(fn_type, function, &[], then_block, catch_block, "get_pi"); + let pi2_call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -351,7 +351,7 @@ fn test_null_checked_ptr_ops() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let index1 = builder.build_load(new_ptr, "deref"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let index1 = builder.build_load_2(i8_ptr_type, new_ptr, "deref"); + let index1 = builder.build_load(i8_ptr_type, new_ptr, "deref"); builder.build_return(Some(&index1)); @@ -391,7 +391,7 @@ fn test_null_checked_ptr_ops() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let index1 = builder.build_load(new_ptr, "deref"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let index1 = builder.build_load_2(i8_ptr_type, new_ptr, "deref"); + let index1 = builder.build_load(i8_ptr_type, new_ptr, "deref"); builder.build_return(Some(&index1)); @@ -903,7 +903,7 @@ fn test_insert_value() { let array = builder.build_load(array_alloca, "array_load").into_array_value(); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] let array = builder - .build_load_2(array_type, array_alloca, "array_load") + .build_load(array_type, array_alloca, "array_load") .into_array_value(); let const_int1 = i32_type.const_int(2, false); let const_int2 = i32_type.const_int(5, false); @@ -935,7 +935,7 @@ fn test_insert_value() { let struct_value = builder.build_load(struct_alloca, "struct_load").into_struct_value(); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] let struct_value = builder - .build_load_2(struct_type, struct_alloca, "struct_load") + .build_load(struct_type, struct_alloca, "struct_load") .into_struct_value(); assert!(builder @@ -1040,7 +1040,7 @@ fn run_memcpy_on<'ctx>( #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let elem_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; + let elem_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); builder.build_store(elem_ptr, int_val); @@ -1054,7 +1054,7 @@ fn run_memcpy_on<'ctx>( #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let dest_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; + let dest_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; builder.build_memcpy(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1117,7 +1117,7 @@ fn run_memmove_on<'ctx>( #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let elem_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; + let elem_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); builder.build_store(elem_ptr, int_val); @@ -1131,7 +1131,7 @@ fn run_memmove_on<'ctx>( #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let dest_ptr = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index_val], "index") }; + let dest_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; builder.build_memmove(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1201,7 +1201,7 @@ fn run_memset_on<'ctx>( #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let part_2 = unsafe { builder.build_in_bounds_gep(array_ptr, &[index], "index") }; #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let part_2 = unsafe { builder.build_in_bounds_gep_2(array_type, array_ptr, &[index], "index") }; + let part_2 = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index], "index") }; builder.build_memset(part_2, alignment, val, size_val)?; builder.build_return(Some(&array_ptr)); @@ -1505,16 +1505,12 @@ fn test_safe_struct_gep() { } #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] { - assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 0, "struct_gep").is_err()); - assert!(builder.build_struct_gep_2(i32_ty, i32_ptr, 10, "struct_gep").is_err()); + 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()); + assert!(builder.build_struct_gep(struct_ty, struct_ptr, 0, "struct_gep").is_ok()); + assert!(builder.build_struct_gep(struct_ty, struct_ptr, 1, "struct_gep").is_ok()); assert!(builder - .build_struct_gep_2(struct_ty, struct_ptr, 0, "struct_gep") - .is_ok()); - assert!(builder - .build_struct_gep_2(struct_ty, struct_ptr, 1, "struct_gep") - .is_ok()); - assert!(builder - .build_struct_gep_2(struct_ty, struct_ptr, 2, "struct_gep") + .build_struct_gep(struct_ty, struct_ptr, 2, "struct_gep") .is_err()); } } diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index 63f57cb04fb..968ef6646c1 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -420,7 +420,7 @@ fn test_mem_instructions() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let load = builder.build_load(arg1, ""); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let load = builder.build_load_2(f32_ptr_type, arg1, ""); + let load = builder.build_load(f32_ptr_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); assert_eq!(store_instruction.get_volatile().unwrap(), false); @@ -486,7 +486,7 @@ fn test_atomic_ordering_mem_instructions() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let load = builder.build_load(arg1, ""); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let load = builder.build_load_2(f32_ptr_type, arg1, ""); + let load = builder.build_load(f32_ptr_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); assert_eq!( diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index 2fd29e0810e..21e69d697fa 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -42,7 +42,7 @@ fn test_call_site() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] let call_site = builder.build_call(function, &[], "to_infinity_and_beyond"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - let call_site = builder.build_call_2(fn_type, function, &[], "to_infinity_and_beyond"); + let call_site = builder.build_call(fn_type, function, &[], "to_infinity_and_beyond"); assert_eq!(call_site.count_arguments(), 0); assert!(!call_site.is_tail_call()); @@ -1153,7 +1153,7 @@ fn test_non_fn_ptr_called() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] builder.build_call(callable_value, &[], "call"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - builder.build_call_2(i8_ptr_type.fn_type(&[], false), callable_value, &[], "call"); + builder.build_call(i8_ptr_type.fn_type(&[], false), callable_value, &[], "call"); builder.build_return(None); assert!(module.verify().is_ok()); @@ -1203,7 +1203,7 @@ fn test_aggregate_returns() { #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] builder.build_ptr_diff(ptr_param1, ptr_param2, "diff"); #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] - builder.build_ptr_diff_2(i32_ptr_type, ptr_param1, ptr_param2, "diff"); + builder.build_ptr_diff(i32_ptr_type, ptr_param1, ptr_param2, "diff"); builder.build_aggregate_return(&[i32_three.into(), i32_seven.into()]); assert!(module.verify().is_ok()); From 34c30f8381d91cd0d281e51390184a51a33b5fab Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 27 Nov 2022 11:16:07 +0200 Subject: [PATCH 17/34] Remove the command line arguments parsing function --- src/support/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/support/mod.rs b/src/support/mod.rs index 08aa31cef1f..ea95f2d45ec 100644 --- a/src/support/mod.rs +++ b/src/support/mod.rs @@ -5,7 +5,6 @@ use libc::c_char; use llvm_sys::core::{LLVMCreateMessage, LLVMDisposeMessage}; use llvm_sys::error_handling::LLVMEnablePrettyStackTrace; use llvm_sys::support::LLVMLoadLibraryPermanently; -use llvm_sys::support::LLVMParseCommandLineOptions; use std::borrow::Cow; use std::error::Error; @@ -124,15 +123,6 @@ pub unsafe fn shutdown_llvm() { LLVMShutdown() } -pub fn parse_command_line_options(argc: i32, argv: &[&str], overview: &str) { - let argv: Vec<*const ::libc::c_char> = argv.iter().map(|arg| to_c_str(arg).as_ptr()).collect(); - let overview = to_c_str(overview); - - unsafe { - LLVMParseCommandLineOptions(argc, argv.as_ptr(), overview.as_ptr()); - } -} - pub fn load_library_permanently(filename: &str) -> bool { let filename = to_c_str(filename); From b0ae971f9a70c78e4e9696843a9dc3a4d95ef900 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Thu, 1 Dec 2022 11:08:51 +0200 Subject: [PATCH 18/34] Remove another function type check --- src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index d99f0b93759..af1bf014763 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -469,7 +469,7 @@ impl<'ctx> Builder<'ctx> { let fn_val_ref = callable_value.as_value_ref(); // LLVM gets upset when void return calls are named because they don't return anything - let name = if callable_value.returns_void() { "" } else { name }; + let name = if fn_ty.get_return_type().is_none() { "" } else { name }; let c_string = to_c_str(name); let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); From e5dce8bd9254c653591197212bfa50a7c01afa78 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Fri, 2 Dec 2022 10:39:16 +0200 Subject: [PATCH 19/34] Restore bitcast; some minor improvements --- src/attributes.rs | 4 ++-- src/builder.rs | 37 ++++++++++++++++++------------------ src/context.rs | 4 ++-- src/module.rs | 4 ++-- src/passes.rs | 8 ++++---- src/types/metadata_type.rs | 2 +- src/values/callable_value.rs | 5 ++++- src/values/float_value.rs | 10 +++++----- src/values/global_value.rs | 6 +++--- src/values/int_value.rs | 12 ++++++------ src/values/mod.rs | 7 +++---- src/values/ptr_value.rs | 6 +++--- src/values/traits.rs | 4 ++-- tests/all/test_values.rs | 2 +- 14 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index 8a8abfaab1f..c2587434ad8 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -121,7 +121,7 @@ impl Attribute { /// /// assert_eq!(enum_attribute.get_enum_kind_id(), 0); /// ``` - #[llvm_versions(4.0..12.0)] + #[llvm_versions(4.0..=11.0)] pub fn get_enum_kind_id(self) -> u32 { assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes @@ -165,7 +165,7 @@ impl Attribute { unsafe { LLVMGetEnumAttributeKind(self.attribute) } } - #[llvm_versions(4.0..12.0)] + #[llvm_versions(4.0..=11.0)] fn get_enum_kind_id_is_valid(self) -> bool { self.is_enum() } diff --git a/src/builder.rs b/src/builder.rs index af1bf014763..4b0472338d1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -19,7 +19,7 @@ use llvm_sys::core::{ LLVMInsertIntoBuilderWithName, LLVMPositionBuilder, LLVMPositionBuilderAtEnd, LLVMPositionBuilderBefore, LLVMSetCleanup, }; -#[llvm_versions(4.0..14.0)] +#[llvm_versions(4.0..=13.0)] use llvm_sys::core::{ LLVMBuildCall, LLVMBuildGEP, LLVMBuildInBoundsGEP, LLVMBuildInvoke, LLVMBuildLoad, LLVMBuildPtrDiff, LLVMBuildStructGEP, @@ -38,13 +38,11 @@ use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; use crate::support::to_c_str; -use crate::types::{ - AnyType, AsTypeRef, BasicType, FloatMathType, FunctionType, IntMathType, PointerMathType, PointerType, -}; +use crate::types::{AsTypeRef, BasicType, FloatMathType, FunctionType, IntMathType, PointerMathType, PointerType}; use crate::values::{ - AggregateValue, AggregateValueEnum, AnyValue, AnyValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, - BasicValueEnum, CallSiteValue, CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, - InstructionValue, IntMathValue, IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, + AggregateValue, AggregateValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, + CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, InstructionValue, IntMathValue, + IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, }; #[cfg(feature = "internal-getters")] use crate::LLVMReference; @@ -164,7 +162,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&ret_val)); /// ``` - #[llvm_versions(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub fn build_call(&self, function: F, args: &[BasicMetadataValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx> where F: Into>, @@ -336,7 +334,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&f32_type.const_zero())); /// } /// ``` - #[llvm_versions(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub fn build_invoke( &self, function: F, @@ -745,7 +743,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(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub unsafe fn build_gep( &self, ptr: PointerValue<'ctx>, @@ -796,7 +794,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(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub unsafe fn build_in_bounds_gep( &self, ptr: PointerValue<'ctx>, @@ -878,7 +876,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(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub fn build_struct_gep(&self, ptr: PointerValue<'ctx>, index: u32, name: &str) -> Result, ()> { let ptr_ty = ptr.get_type(); let pointee_ty = ptr_ty.get_element_type(); @@ -994,7 +992,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_ptr_diff(i32_ptr_param1, i32_ptr_param2, "diff"); /// builder.build_return(None); /// ``` - #[llvm_versions(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub fn build_ptr_diff( &self, lhs_ptr: PointerValue<'ctx>, @@ -1130,7 +1128,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&pointee)); /// ``` - #[llvm_versions(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); @@ -1455,6 +1453,7 @@ impl<'ctx> Builder<'ctx> { /// # Example /// /// ```no_run + /// use inkwell::AddressSpace; /// use inkwell::context::Context; /// /// let context = Context::create(); @@ -1463,7 +1462,7 @@ impl<'ctx> Builder<'ctx> { /// let f32_type = context.f32_type(); /// let i32_type = context.i32_type(); /// let arg_types = [i32_type.into()]; - /// let fn_type = void_type.fn_type(&arg_types, false); + /// let fn_type = void_type.fn_type(&arg_types, false).ptr_type(AddressSpace::Zero); /// let fn_value = module.add_function("bc", fn_type, None); /// let builder = context.create_builder(); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -1476,16 +1475,16 @@ impl<'ctx> Builder<'ctx> { /// /// assert!(module.verify().is_ok()); /// ``` - pub fn build_bitcast(&self, val: V, ty: T, name: &str) -> AnyValueEnum<'ctx> + pub fn build_bitcast(&self, val: V, ty: T, name: &str) -> BasicValueEnum<'ctx> where - T: AnyType<'ctx>, - V: AnyValue<'ctx>, + T: BasicType<'ctx>, + V: BasicValue<'ctx>, { let c_string = to_c_str(name); let value = unsafe { LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr()) }; - unsafe { AnyValueEnum::new(value) } + unsafe { BasicValueEnum::new(value) } } pub fn build_int_s_extend_or_bit_cast>( diff --git a/src/context.rs b/src/context.rs index 97d54b9d3df..e954b71ba8a 100644 --- a/src/context.rs +++ b/src/context.rs @@ -3,13 +3,13 @@ #[llvm_versions(7.0..=latest)] use crate::InlineAsmDialect; use libc::c_void; -#[llvm_versions(4.0..7.0)] +#[llvm_versions(4.0..=6.0)] use llvm_sys::core::LLVMConstInlineAsm; #[llvm_versions(12.0..=latest)] use llvm_sys::core::LLVMCreateTypeAttribute; #[llvm_versions(7.0..=latest)] use llvm_sys::core::LLVMGetInlineAsm; -#[llvm_versions(4.0..12.0)] +#[llvm_versions(4.0..=11.0)] use llvm_sys::core::LLVMGetTypeByName; #[llvm_versions(12.0..=latest)] use llvm_sys::core::LLVMGetTypeByName2; diff --git a/src/module.rs b/src/module.rs index 64b406a7cb0..c942d182563 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,7 +4,7 @@ use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyModule}; #[allow(deprecated)] use llvm_sys::bit_reader::LLVMParseBitcodeInContext; use llvm_sys::bit_writer::{LLVMWriteBitcodeToFile, LLVMWriteBitcodeToMemoryBuffer}; -#[llvm_versions(4.0..14.0)] +#[llvm_versions(4.0..=13.0)] use llvm_sys::core::LLVMGetTypeByName; use llvm_sys::core::{ @@ -348,7 +348,7 @@ impl<'ctx> Module<'ctx> { /// assert_eq!(module.get_struct_type("foo").unwrap(), opaque); /// ``` /// - #[llvm_versions(4.0..12.0)] + #[llvm_versions(4.0..=11.0)] pub fn get_struct_type(&self, name: &str) -> Option> { let c_string = to_c_str(name); diff --git a/src/passes.rs b/src/passes.rs index e51bb348a97..e24f511d453 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -181,7 +181,7 @@ impl PassManagerBuilder { /// /// pass_manager_builder.populate_lto_pass_manager(&lpm, false, false); /// ``` - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) { unsafe { LLVMPassManagerBuilderPopulateLTOPassManager( @@ -299,7 +299,7 @@ impl PassManager { /// only stored to (returning the value instead), but does not currently. /// This case would be best handled when and if LLVM starts supporting multiple /// return values from functions. - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn add_argument_promotion_pass(&self) { unsafe { LLVMAddArgumentPromotionPass(self.pass_manager) } } @@ -721,7 +721,7 @@ impl PassManager { /// to be run before it to hoist invariant conditions /// out of the loop, to make the unswitching opportunity /// obvious. - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn add_loop_unswitch_pass(&self) { use llvm_sys::core::LLVMAddLoopUnswitchPass; @@ -760,7 +760,7 @@ impl PassManager { /// order to rewrite loads and stores as appropriate. This is just /// the standard SSA construction algorithm to construct "pruned" SSA form. pub fn add_promote_memory_to_register_pass(&self) { - #[llvm_versions(4.0..7.0)] + #[llvm_versions(4.0..=6.0)] use llvm_sys::transforms::scalar::LLVMAddPromoteMemoryToRegisterPass; #[llvm_versions(7.0..=latest)] use llvm_sys::transforms::util::LLVMAddPromoteMemoryToRegisterPass; diff --git a/src/types/metadata_type.rs b/src/types/metadata_type.rs index c386b3cd558..fb164691d69 100644 --- a/src/types/metadata_type.rs +++ b/src/types/metadata_type.rs @@ -73,7 +73,7 @@ impl AsTypeRef for MetadataType<'_> { self.metadata_type.ty } - #[llvm_versions(4.0..6.0)] + #[llvm_versions(4.0..=5.0)] fn as_type_ref(&self) -> LLVMTypeRef { unimplemented!("MetadataType is only available in LLVM > 6.0") } diff --git a/src/values/callable_value.rs b/src/values/callable_value.rs index 02a2d094466..a5300ef8226 100644 --- a/src/values/callable_value.rs +++ b/src/values/callable_value.rs @@ -6,7 +6,7 @@ use crate::types::AsTypeRef; use crate::values::AsValueRef; use crate::values::{AnyValue, FunctionValue, PointerValue}; -use llvm_sys::core::{LLVMGetElementType, LLVMGetReturnType, LLVMGetTypeKind, LLVMTypeOf}; +use llvm_sys::core::{LLVMGetElementType, LLVMGetTypeKind, LLVMTypeOf}; use llvm_sys::prelude::LLVMTypeRef; use llvm_sys::prelude::LLVMValueRef; use llvm_sys::LLVMTypeKind; @@ -104,7 +104,10 @@ impl<'ctx> AsTypeRef for CallableValue<'ctx> { } impl<'ctx> CallableValue<'ctx> { + #[llvm_versions(4.0..=13.0)] pub(crate) fn returns_void(&self) -> bool { + use llvm_sys::core::LLVMGetReturnType; + let return_type = unsafe { LLVMGetTypeKind(LLVMGetReturnType(LLVMGetElementType(LLVMTypeOf(self.as_value_ref())))) }; diff --git a/src/values/float_value.rs b/src/values/float_value.rs index 627ed86f58a..7a87e691965 100644 --- a/src/values/float_value.rs +++ b/src/values/float_value.rs @@ -64,35 +64,35 @@ impl<'ctx> FloatValue<'ctx> { unsafe { FloatValue::new(LLVMConstFNeg(self.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_add(self, rhs: FloatValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstFAdd; unsafe { FloatValue::new(LLVMConstFAdd(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_sub(self, rhs: FloatValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstFSub; unsafe { FloatValue::new(LLVMConstFSub(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_mul(self, rhs: FloatValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstFMul; unsafe { FloatValue::new(LLVMConstFMul(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_div(self, rhs: FloatValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstFDiv; unsafe { FloatValue::new(LLVMConstFDiv(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_remainder(self, rhs: FloatValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstFRem; diff --git a/src/values/global_value.rs b/src/values/global_value.rs index aa5afb4db17..38dd68f3613 100644 --- a/src/values/global_value.rs +++ b/src/values/global_value.rs @@ -1,6 +1,6 @@ #[llvm_versions(8.0..=latest)] use llvm_sys::core::LLVMGlobalSetMetadata; -#[llvm_versions(4.0..8.0)] +#[llvm_versions(4.0..=7.0)] use llvm_sys::core::{ LLVMDeleteGlobal, LLVMGetAlignment, LLVMGetDLLStorageClass, LLVMGetInitializer, LLVMGetLinkage, LLVMGetNextGlobal, LLVMGetPreviousGlobal, LLVMGetSection, LLVMGetThreadLocalMode, LLVMGetVisibility, LLVMIsDeclaration, @@ -161,7 +161,7 @@ impl<'ctx> GlobalValue<'ctx> { unsafe { LLVMIsDeclaration(self.as_value_ref()) == 1 } } - #[llvm_versions(4.0..7.0)] + #[llvm_versions(4.0..=6.0)] pub fn has_unnamed_addr(self) -> bool { unsafe { LLVMHasUnnamedAddr(self.as_value_ref()) == 1 } } @@ -171,7 +171,7 @@ impl<'ctx> GlobalValue<'ctx> { unsafe { LLVMGetUnnamedAddress(self.as_value_ref()) == LLVMUnnamedAddr::LLVMGlobalUnnamedAddr } } - #[llvm_versions(4.0..7.0)] + #[llvm_versions(4.0..=6.0)] pub fn set_unnamed_addr(self, has_unnamed_addr: bool) { unsafe { LLVMSetUnnamedAddr(self.as_value_ref(), has_unnamed_addr as i32) } } diff --git a/src/values/int_value.rs b/src/values/int_value.rs index c38773f1f74..db00cc858b5 100644 --- a/src/values/int_value.rs +++ b/src/values/int_value.rs @@ -117,42 +117,42 @@ impl<'ctx> IntValue<'ctx> { unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstUDiv; unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstSDiv; unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstExactSDiv; unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstExactUDiv; unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstURem; unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) } } - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self { use llvm_sys::core::LLVMConstSRem; diff --git a/src/values/mod.rs b/src/values/mod.rs index 38d1131eeb4..008f64aaadf 100644 --- a/src/values/mod.rs +++ b/src/values/mod.rs @@ -101,13 +101,12 @@ impl<'ctx> Value<'ctx> { // add a ParamValue wrapper type that always have it but conditional types (IntValue) // that also have it. This isn't a huge deal though, since it hasn't proven to be UB so far 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 crate::support::to_c_str; use llvm_sys::core::LLVMSetValueName; - let c_string = to_c_str(name); - unsafe { LLVMSetValueName(self.value, c_string.as_ptr()); } @@ -116,7 +115,7 @@ impl<'ctx> Value<'ctx> { { use llvm_sys::core::LLVMSetValueName2; - unsafe { LLVMSetValueName2(self.value, name.as_ptr() as *const ::libc::c_char, name.len()) } + unsafe { LLVMSetValueName2(self.value, c_string.as_ptr(), name.len()) } } } diff --git a/src/values/ptr_value.rs b/src/values/ptr_value.rs index 5bf09763ad6..61948b6ad0f 100644 --- a/src/values/ptr_value.rs +++ b/src/values/ptr_value.rs @@ -1,4 +1,4 @@ -#[llvm_versions(4.0..14.0)] +#[llvm_versions(4.0..=13.0)] use llvm_sys::core::{LLVMConstGEP, LLVMConstInBoundsGEP}; #[llvm_versions(14.0..=latest)] use llvm_sys::core::{LLVMConstGEP2, LLVMConstInBoundsGEP2}; @@ -77,7 +77,7 @@ 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(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] 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(); @@ -111,7 +111,7 @@ 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(4.0..14.0)] + #[llvm_versions(4.0..=13.0)] 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(); diff --git a/src/values/traits.rs b/src/values/traits.rs index bae2dde75e3..4fb6c51e0d6 100644 --- a/src/values/traits.rs +++ b/src/values/traits.rs @@ -54,7 +54,7 @@ pub trait AggregateValue<'ctx>: BasicValue<'ctx> { // REVIEW: How does LLVM treat out of bound index? Maybe we should return an Option? // or is that only in bounds GEP // REVIEW: Should this be AggregatePointerValue? - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] fn const_extract_value(&self, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { use llvm_sys::core::LLVMConstExtractValue; @@ -68,7 +68,7 @@ pub trait AggregateValue<'ctx>: BasicValue<'ctx> { } // SubTypes: value should really be T in self: VectorValue I think - #[llvm_versions(4.0..15.0)] + #[llvm_versions(4.0..=14.0)] fn const_insert_value>(&self, value: BV, indexes: &mut [u32]) -> BasicValueEnum<'ctx> { use llvm_sys::core::LLVMConstInsertValue; diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index 21e69d697fa..3d62935e581 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -525,7 +525,7 @@ fn test_metadata() { #[test] fn test_floats() { - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] { use inkwell::FloatPredicate; From 4aa2f42ce33e9e9ddda62434c2e604f427f9033d Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sat, 10 Dec 2022 09:31:27 +0200 Subject: [PATCH 20/34] Merge the CI changes --- .github/workflows/test.yml | 2 +- Cargo.toml | 2 +- internal_macros/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a96c840a50..1563178c7af 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-20.04] llvm-version: - ["4.0", "4-0"] - ["5.0", "5-0"] diff --git a/Cargo.toml b/Cargo.toml index a153cda90ab..cf146be5a2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,7 @@ internal-getters = [] [dependencies] either = "1.5" -inkwell_internals = { path = "./internal_macros", version = "0.5.0" } +inkwell_internals = { path = "./internal_macros", version = "0.6.0" } libc = "0.2" llvm-sys-40 = { package = "llvm-sys", version = "40.4", optional = true } llvm-sys-50 = { package = "llvm-sys", version = "50.4", optional = true } diff --git a/internal_macros/Cargo.toml b/internal_macros/Cargo.toml index aa6b818b8ef..680ec17c39e 100644 --- a/internal_macros/Cargo.toml +++ b/internal_macros/Cargo.toml @@ -6,7 +6,7 @@ license = "Apache-2.0" name = "inkwell_internals" readme = "README.md" repository = "https://github.com/TheDan64/inkwell" -version = "0.5.0" +version = "0.6.0" [dependencies] proc-macro2 = "1.0" From 9bc6a160e49ed8d895908d7272801592d1d99c62 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 11 Dec 2022 16:06:04 +0200 Subject: [PATCH 21/34] Fix LLVM version 5 --- src/builder.rs | 81 ++++++++++++++++++-------------------------------- src/passes.rs | 6 +++- 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 4b0472338d1..764c917a160 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2747,36 +2747,24 @@ impl<'ctx> Builder<'ctx> { } /// Set the debug info source location of the instruction currently pointed at by the builder + #[llvm_versions(7.0..=8.0)] pub fn set_current_debug_location(&self, context: &'ctx crate::context::Context, location: DILocation<'ctx>) { - #[cfg(any( - feature = "llvm4-0", - feature = "llvm5-0", - feature = "llvm6-0", - feature = "llvm7-0", - feature = "llvm8-0" - ))] - { - use llvm_sys::core::LLVMMetadataAsValue; - use llvm_sys::core::LLVMSetCurrentDebugLocation; - unsafe { - LLVMSetCurrentDebugLocation( - self.builder, - LLVMMetadataAsValue(context.context.0, location.metadata_ref), - ); - } + use llvm_sys::core::LLVMMetadataAsValue; + use llvm_sys::core::LLVMSetCurrentDebugLocation; + unsafe { + LLVMSetCurrentDebugLocation( + self.builder, + LLVMMetadataAsValue(context.context.0, location.metadata_ref), + ); } - #[cfg(not(any( - feature = "llvm4-0", - feature = "llvm5-0", - feature = "llvm6-0", - feature = "llvm7-0", - feature = "llvm8-0" - )))] - { - use llvm_sys::core::LLVMSetCurrentDebugLocation2; - unsafe { - LLVMSetCurrentDebugLocation2(self.builder, location.metadata_ref); - } + } + + /// Set the debug info source location of the instruction currently pointed at by the builder + #[llvm_versions(9.0..=latest)] + pub fn set_current_debug_location(&self, location: DILocation<'ctx>) { + use llvm_sys::core::LLVMSetCurrentDebugLocation2; + unsafe { + LLVMSetCurrentDebugLocation2(self.builder, location.metadata_ref); } } @@ -2798,32 +2786,21 @@ 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.0..=8.0)] pub fn unset_current_debug_location(&self) { - #[cfg(any( - feature = "llvm4-0", - feature = "llvm5-0", - feature = "llvm6-0", - feature = "llvm7-0", - feature = "llvm8-0" - ))] - { - use llvm_sys::core::LLVMSetCurrentDebugLocation; - unsafe { - LLVMSetCurrentDebugLocation(self.builder, std::ptr::null_mut()); - } + use llvm_sys::core::LLVMSetCurrentDebugLocation; + unsafe { + LLVMSetCurrentDebugLocation(self.builder, std::ptr::null_mut()); } - #[cfg(not(any( - feature = "llvm4-0", - feature = "llvm5-0", - feature = "llvm6-0", - feature = "llvm7-0", - feature = "llvm8-0" - )))] - { - use llvm_sys::core::LLVMSetCurrentDebugLocation2; - unsafe { - LLVMSetCurrentDebugLocation2(self.builder, std::ptr::null_mut()); - } + } + + /// 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(9.0..=latest)] + pub fn unset_current_debug_location(&self) { + use llvm_sys::core::LLVMSetCurrentDebugLocation2; + unsafe { + LLVMSetCurrentDebugLocation2(self.builder, std::ptr::null_mut()); } } } diff --git a/src/passes.rs b/src/passes.rs index e24f511d453..0cd6ee88ee5 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -183,6 +183,8 @@ impl PassManagerBuilder { /// ``` #[llvm_versions(4.0..=14.0)] pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) { + use llvm_sys::core::LLVMPassManagerBuilderPopulateLTOPassManager; + unsafe { LLVMPassManagerBuilderPopulateLTOPassManager( self.pass_manager_builder, @@ -301,6 +303,8 @@ impl PassManager { /// return values from functions. #[llvm_versions(4.0..=14.0)] pub fn add_argument_promotion_pass(&self) { + use llvm_sys::transforms::ipo::LLVMAddArgumentPromotionPass; + unsafe { LLVMAddArgumentPromotionPass(self.pass_manager) } } @@ -723,7 +727,7 @@ impl PassManager { /// obvious. #[llvm_versions(4.0..=14.0)] pub fn add_loop_unswitch_pass(&self) { - use llvm_sys::core::LLVMAddLoopUnswitchPass; + use llvm_sys::transforms::scalar::LLVMAddLoopUnswitchPass; unsafe { LLVMAddLoopUnswitchPass(self.pass_manager) } } From 241c733aa02f8935696b4e5e8ff2e02e37fba1d9 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 16:08:05 +0200 Subject: [PATCH 22/34] Fix the LTO pass manager import --- src/passes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes.rs b/src/passes.rs index 0cd6ee88ee5..41adb4e39cf 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -183,7 +183,7 @@ impl PassManagerBuilder { /// ``` #[llvm_versions(4.0..=14.0)] pub fn populate_lto_pass_manager(&self, pass_manager: &PassManager, internalize: bool, run_inliner: bool) { - use llvm_sys::core::LLVMPassManagerBuilderPopulateLTOPassManager; + use llvm_sys::transforms::pass_manager_builder::LLVMPassManagerBuilderPopulateLTOPassManager; unsafe { LLVMPassManagerBuilderPopulateLTOPassManager( From 966861c83ee455a430d92a965f956c698a066b6b Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 16:39:43 +0200 Subject: [PATCH 23/34] Fix the debug info test --- tests/all/test_debug_info.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/all/test_debug_info.rs b/tests/all/test_debug_info.rs index 913086c1459..e5ed2fb7e87 100644 --- a/tests/all/test_debug_info.rs +++ b/tests/all/test_debug_info.rs @@ -79,7 +79,11 @@ fn test_smoke() { let lexical_block = dibuilder.create_lexical_block(func_scope.as_debug_info_scope(), compile_unit.get_file(), 0, 0); let loc = dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None); + + #[cfg(any(feature = "llvm7-0", feature = "llvm8-0",))] builder.set_current_debug_location(&context, loc); + #[cfg(not(any(feature = "llvm7-0", feature = "llvm8-0",)))] + builder.set_current_debug_location(loc); dibuilder.finalize(); From 7a83275034989ac91e76e38c3b963e63fd31e1e2 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 16:52:07 +0200 Subject: [PATCH 24/34] Improve namings; potential fix for the struct_gep segfault --- src/builder.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 764c917a160..f52e7d55bd4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -770,7 +770,7 @@ impl<'ctx> Builder<'ctx> { #[llvm_versions(14.0..=latest)] pub unsafe fn build_gep>( &self, - ty: T, + pointee_ty: T, ptr: PointerValue<'ctx>, ordered_indexes: &[IntValue<'ctx>], name: &str, @@ -781,7 +781,7 @@ impl<'ctx> Builder<'ctx> { let value = LLVMBuildGEP2( self.builder, - ty.as_type_ref(), + pointee_ty.as_type_ref(), ptr.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, @@ -822,7 +822,7 @@ impl<'ctx> Builder<'ctx> { #[llvm_versions(14.0..=latest)] pub unsafe fn build_in_bounds_gep>( &self, - ty: T, + pointee_ty: T, ptr: PointerValue<'ctx>, ordered_indexes: &[IntValue<'ctx>], name: &str, @@ -833,7 +833,7 @@ impl<'ctx> Builder<'ctx> { let value = LLVMBuildInBoundsGEP2( self.builder, - ty.as_type_ref(), + pointee_ty.as_type_ref(), ptr.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, @@ -934,13 +934,12 @@ impl<'ctx> Builder<'ctx> { #[llvm_versions(14.0..=latest)] pub fn build_struct_gep>( &self, - ty: T, + pointee_ty: T, ptr: PointerValue<'ctx>, index: u32, name: &str, ) -> Result, ()> { - let ptr_ty = ptr.get_type(); - let pointee_ty = ptr_ty.get_element_type(); + let pointee_ty = pointee_ty.as_any_type_enum(); if !pointee_ty.is_struct_type() { return Err(()); @@ -957,7 +956,7 @@ impl<'ctx> Builder<'ctx> { let value = unsafe { LLVMBuildStructGEP2( self.builder, - ty.as_type_ref(), + pointee_ty.as_type_ref(), ptr.as_value_ref(), index, c_string.as_ptr(), @@ -1040,7 +1039,7 @@ impl<'ctx> Builder<'ctx> { #[llvm_versions(14.0..=latest)] pub fn build_ptr_diff>( &self, - ty: T, + pointee_ty: T, lhs_ptr: PointerValue<'ctx>, rhs_ptr: PointerValue<'ctx>, name: &str, @@ -1050,7 +1049,7 @@ impl<'ctx> Builder<'ctx> { let value = unsafe { LLVMBuildPtrDiff2( self.builder, - ty.as_type_ref(), + pointee_ty.as_type_ref(), lhs_ptr.as_value_ref(), rhs_ptr.as_value_ref(), c_string.as_ptr(), @@ -1163,10 +1162,22 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&pointee)); /// ``` #[llvm_versions(14.0..=latest)] - pub fn build_load>(&self, ty: T, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { + pub fn build_load>( + &self, + pointee_ty: T, + ptr: PointerValue<'ctx>, + name: &str, + ) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); - let value = unsafe { LLVMBuildLoad2(self.builder, ty.as_type_ref(), ptr.as_value_ref(), c_string.as_ptr()) }; + let value = unsafe { + LLVMBuildLoad2( + self.builder, + pointee_ty.as_type_ref(), + ptr.as_value_ref(), + c_string.as_ptr(), + ) + }; unsafe { BasicValueEnum::new(value) } } From c5757b7aeaaf8a8cfe13f5b3511c76da4937cc54 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 17:03:55 +0200 Subject: [PATCH 25/34] Bump changes version from >=14 to >=15 --- src/builder.rs | 32 ++++++++++++++++---------------- src/module.rs | 2 +- src/values/callable_value.rs | 2 +- src/values/ptr_value.rs | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f52e7d55bd4..db2e8bbcc8b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -19,12 +19,12 @@ use llvm_sys::core::{ LLVMInsertIntoBuilderWithName, LLVMPositionBuilder, LLVMPositionBuilderAtEnd, LLVMPositionBuilderBefore, LLVMSetCleanup, }; -#[llvm_versions(4.0..=13.0)] +#[llvm_versions(4.0..=14.0)] use llvm_sys::core::{ LLVMBuildCall, LLVMBuildGEP, LLVMBuildInBoundsGEP, LLVMBuildInvoke, LLVMBuildLoad, LLVMBuildPtrDiff, LLVMBuildStructGEP, }; -#[llvm_versions(14.0..=latest)] +#[llvm_versions(15.0..=latest)] use llvm_sys::core::{ LLVMBuildCall2, LLVMBuildGEP2, LLVMBuildInBoundsGEP2, LLVMBuildInvoke2, LLVMBuildLoad2, LLVMBuildPtrDiff2, LLVMBuildStructGEP2, @@ -162,7 +162,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&ret_val)); /// ``` - #[llvm_versions(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub fn build_call(&self, function: F, args: &[BasicMetadataValueEnum<'ctx>], name: &str) -> CallSiteValue<'ctx> where F: Into>, @@ -220,7 +220,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&ret_val)); /// ``` - #[llvm_versions(14.0..=latest)] + #[llvm_versions(15.0..=latest)] pub fn build_call( &self, fn_ty: FunctionType<'ctx>, @@ -334,7 +334,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&f32_type.const_zero())); /// } /// ``` - #[llvm_versions(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub fn build_invoke( &self, function: F, @@ -449,7 +449,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&f32_type.const_zero())); /// } /// ``` - #[llvm_versions(14.0..=latest)] + #[llvm_versions(15.0..=latest)] pub fn build_invoke( &self, fn_ty: FunctionType<'ctx>, @@ -743,7 +743,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(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub unsafe fn build_gep( &self, ptr: PointerValue<'ctx>, @@ -767,7 +767,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.0..=latest)] + #[llvm_versions(15.0..=latest)] pub unsafe fn build_gep>( &self, pointee_ty: T, @@ -794,7 +794,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(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub unsafe fn build_in_bounds_gep( &self, ptr: PointerValue<'ctx>, @@ -819,7 +819,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.0..=latest)] + #[llvm_versions(15.0..=latest)] pub unsafe fn build_in_bounds_gep>( &self, pointee_ty: T, @@ -876,7 +876,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(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub fn build_struct_gep(&self, ptr: PointerValue<'ctx>, index: u32, name: &str) -> Result, ()> { let ptr_ty = ptr.get_type(); let pointee_ty = ptr_ty.get_element_type(); @@ -931,7 +931,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(14.0..=latest)] + #[llvm_versions(15.0..=latest)] pub fn build_struct_gep>( &self, pointee_ty: T, @@ -991,7 +991,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_ptr_diff(i32_ptr_param1, i32_ptr_param2, "diff"); /// builder.build_return(None); /// ``` - #[llvm_versions(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub fn build_ptr_diff( &self, lhs_ptr: PointerValue<'ctx>, @@ -1036,7 +1036,7 @@ impl<'ctx> Builder<'ctx> { /// builder.build_ptr_diff(i32_ptr_type, i32_ptr_param1, i32_ptr_param2, "diff"); /// builder.build_return(None); /// ``` - #[llvm_versions(14.0..=latest)] + #[llvm_versions(15.0..=latest)] pub fn build_ptr_diff>( &self, pointee_ty: T, @@ -1127,7 +1127,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&pointee)); /// ``` - #[llvm_versions(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub fn build_load(&self, ptr: PointerValue<'ctx>, name: &str) -> BasicValueEnum<'ctx> { let c_string = to_c_str(name); @@ -1161,7 +1161,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.build_return(Some(&pointee)); /// ``` - #[llvm_versions(14.0..=latest)] + #[llvm_versions(15.0..=latest)] pub fn build_load>( &self, pointee_ty: T, diff --git a/src/module.rs b/src/module.rs index c942d182563..b9acad52092 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,7 +4,7 @@ use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyModule}; #[allow(deprecated)] use llvm_sys::bit_reader::LLVMParseBitcodeInContext; use llvm_sys::bit_writer::{LLVMWriteBitcodeToFile, LLVMWriteBitcodeToMemoryBuffer}; -#[llvm_versions(4.0..=13.0)] +#[llvm_versions(4.0..=14.0)] use llvm_sys::core::LLVMGetTypeByName; use llvm_sys::core::{ diff --git a/src/values/callable_value.rs b/src/values/callable_value.rs index a5300ef8226..cc1fbb73c2a 100644 --- a/src/values/callable_value.rs +++ b/src/values/callable_value.rs @@ -104,7 +104,7 @@ impl<'ctx> AsTypeRef for CallableValue<'ctx> { } impl<'ctx> CallableValue<'ctx> { - #[llvm_versions(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] pub(crate) fn returns_void(&self) -> bool { use llvm_sys::core::LLVMGetReturnType; diff --git a/src/values/ptr_value.rs b/src/values/ptr_value.rs index 61948b6ad0f..c50f7ba313e 100644 --- a/src/values/ptr_value.rs +++ b/src/values/ptr_value.rs @@ -1,6 +1,6 @@ -#[llvm_versions(4.0..=13.0)] +#[llvm_versions(4.0..=14.0)] use llvm_sys::core::{LLVMConstGEP, LLVMConstInBoundsGEP}; -#[llvm_versions(14.0..=latest)] +#[llvm_versions(15.0..=latest)] use llvm_sys::core::{LLVMConstGEP2, LLVMConstInBoundsGEP2}; use llvm_sys::core::{LLVMConstAddrSpaceCast, LLVMConstPointerCast, LLVMConstPtrToInt}; @@ -77,7 +77,7 @@ 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(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] 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(); @@ -94,7 +94,7 @@ 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.0..=latest)] + #[llvm_versions(15.0..=latest)] 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(); @@ -111,7 +111,7 @@ 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(4.0..=13.0)] + #[llvm_versions(4.0..=14.0)] 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(); @@ -127,7 +127,7 @@ 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.0..=latest)] + #[llvm_versions(15.0..=latest)] pub unsafe fn const_in_bounds_gep>( self, ty: T, From 90bbf7f5844a4e11e3966a25beb6365d8ce2bb33 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 17:18:32 +0200 Subject: [PATCH 26/34] Bump changes in tests from version >=14 to >=15 --- tests/all/test_attributes.rs | 4 +- tests/all/test_builder.rs | 64 ++++++++++++++-------------- tests/all/test_instruction_values.rs | 8 ++-- tests/all/test_values.rs | 12 +++--- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/tests/all/test_attributes.rs b/tests/all/test_attributes.rs index 333effc6fda..e6101c37ebb 100644 --- a/tests/all/test_attributes.rs +++ b/tests/all/test_attributes.rs @@ -151,9 +151,9 @@ fn test_attributes_on_call_site_values() { builder.position_at_end(entry_bb); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let call_site_value = builder.build_call(fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let call_site_value = builder.build_call(fn_type, fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); builder.build_return(None); diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs index c00d56506c9..4be7500dfab 100644 --- a/tests/all/test_builder.rs +++ b/tests/all/test_builder.rs @@ -28,9 +28,9 @@ fn test_build_call() { builder.position_at_end(basic_block2); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let pi2_call_site = builder.build_call(function, &[], "get_pi"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let pi2_call_site = builder.build_call(fn_type, function, &[], "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -59,15 +59,15 @@ fn test_build_call() { builder.build_store(alloca, fn_ptr); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let load = builder.build_load(alloca, "load").into_pointer_value(); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let load = builder.build_load(fn_ptr_type, alloca, "load").into_pointer_value(); let callable_value = CallableValue::try_from(load).unwrap(); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] builder.build_call(callable_value, &[], "call"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] builder.build_call(fn_type2, callable_value, &[], "call"); builder.build_return(None); @@ -101,9 +101,9 @@ fn test_build_invoke_cleanup_resume() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!call_site.is_tail_call()); @@ -171,9 +171,9 @@ fn test_build_invoke_catch_all() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let pi2_call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -245,9 +245,9 @@ fn landing_pad_filter() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let pi2_call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -348,9 +348,9 @@ fn test_null_checked_ptr_ops() { let ptr_as_int = builder.build_ptr_to_int(ptr, i64_type, "ptr_as_int"); let new_ptr_as_int = builder.build_int_add(ptr_as_int, one, "add"); let new_ptr = builder.build_int_to_ptr(new_ptr_as_int, i8_ptr_type, "int_as_ptr"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let index1 = builder.build_load(new_ptr, "deref"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let index1 = builder.build_load(i8_ptr_type, new_ptr, "deref"); builder.build_return(Some(&index1)); @@ -388,9 +388,9 @@ fn test_null_checked_ptr_ops() { let ptr_as_int = builder.build_ptr_to_int(ptr, i64_type, "ptr_as_int"); let new_ptr_as_int = builder.build_int_add(ptr_as_int, one, "add"); let new_ptr = builder.build_int_to_ptr(new_ptr_as_int, i8_ptr_type, "int_as_ptr"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let index1 = builder.build_load(new_ptr, "deref"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let index1 = builder.build_load(i8_ptr_type, new_ptr, "deref"); builder.build_return(Some(&index1)); @@ -899,9 +899,9 @@ fn test_insert_value() { builder.position_at_end(entry); let array_alloca = builder.build_alloca(array_type, "array_alloca"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let array = builder.build_load(array_alloca, "array_load").into_array_value(); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let array = builder .build_load(array_type, array_alloca, "array_load") .into_array_value(); @@ -931,9 +931,9 @@ fn test_insert_value() { assert!(builder.build_extract_value(array, 3, "extract").is_none()); let struct_alloca = builder.build_alloca(struct_type, "struct_alloca"); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let struct_value = builder.build_load(struct_alloca, "struct_load").into_struct_value(); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let struct_value = builder .build_load(struct_type, struct_alloca, "struct_load") .into_struct_value(); @@ -1037,9 +1037,9 @@ fn run_memcpy_on<'ctx>( // 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); @@ -1051,9 +1051,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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; builder.build_memcpy(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1114,9 +1114,9 @@ fn run_memmove_on<'ctx>( // 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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); @@ -1128,9 +1128,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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; builder.build_memmove(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1198,9 +1198,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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let part_2 = unsafe { builder.build_in_bounds_gep(array_ptr, &[index], "index") }; - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let part_2 = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index], "index") }; builder.build_memset(part_2, alignment, val, size_val)?; builder.build_return(Some(&array_ptr)); @@ -1495,7 +1495,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(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] { assert!(builder.build_struct_gep(i32_ptr, 0, "struct_gep").is_err()); assert!(builder.build_struct_gep(i32_ptr, 10, "struct_gep").is_err()); @@ -1503,7 +1503,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 = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] { 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_instruction_values.rs b/tests/all/test_instruction_values.rs index 968ef6646c1..a1410941639 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -417,9 +417,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); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let load = builder.build_load(arg1, ""); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let load = builder.build_load(f32_ptr_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); @@ -483,9 +483,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); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let load = builder.build_load(arg1, ""); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let load = builder.build_load(f32_ptr_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index 3d62935e581..d8f071817f2 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -39,9 +39,9 @@ fn test_call_site() { let function = module.add_function("do_nothing", fn_type, None); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] let call_site = builder.build_call(function, &[], "to_infinity_and_beyond"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] let call_site = builder.build_call(fn_type, function, &[], "to_infinity_and_beyond"); assert_eq!(call_site.count_arguments(), 0); @@ -1150,9 +1150,9 @@ fn test_non_fn_ptr_called() { builder.position_at_end(bb); let callable_value = CallableValue::try_from(i8_ptr_param).unwrap(); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] builder.build_call(callable_value, &[], "call"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] builder.build_call(i8_ptr_type.fn_type(&[], false), callable_value, &[], "call"); builder.build_return(None); @@ -1200,9 +1200,9 @@ fn test_aggregate_returns() { let ptr_param2 = fn_value.get_nth_param(1).unwrap().into_pointer_value(); builder.position_at_end(bb); - #[cfg(not(any(feature = "llvm14-0", feature = "llvm15-0")))] + #[cfg(not(feature = "llvm15-0"))] builder.build_ptr_diff(ptr_param1, ptr_param2, "diff"); - #[cfg(any(feature = "llvm14-0", feature = "llvm15-0"))] + #[cfg(feature = "llvm15-0")] builder.build_ptr_diff(i32_ptr_type, ptr_param1, ptr_param2, "diff"); builder.build_aggregate_return(&[i32_three.into(), i32_seven.into()]); From 58f63d50f5c87f6699dd9546ccd8d1f7aaf6e900 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 18:04:48 +0200 Subject: [PATCH 27/34] Fix the bitcast test --- tests/all/test_builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs index 4be7500dfab..8a4a3388345 100644 --- a/tests/all/test_builder.rs +++ b/tests/all/test_builder.rs @@ -1238,7 +1238,7 @@ fn test_memset() { #[test] fn test_bitcast() { - use inkwell::values::AnyValue; + use inkwell::values::BasicValue; let context = Context::create(); let module = context.create_module("bc"); @@ -1279,7 +1279,7 @@ fn test_bitcast() { assert!(module.verify().is_ok(), "{}", module.print_to_string().to_string()); - let first_iv = cast.as_any_value_enum().into_instruction_value(); + let first_iv = cast.as_instruction_value().unwrap(); builder.position_before(&first_iv); builder.build_bitcast(f64_arg, i64_type, "f64toi64"); From f5b8bfe212c535849ed4db8cc1e9340f21f8cfa0 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 18 Dec 2022 18:40:35 +0200 Subject: [PATCH 28/34] Fix some failing tests, replace Generic -> Zero --- src/builder.rs | 20 ++++++++++---------- tests/all/test_passes.rs | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index db2e8bbcc8b..4c77f9f9261 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -323,7 +323,7 @@ impl<'ctx> Builder<'ctx> { /// }; /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -438,7 +438,7 @@ impl<'ctx> Builder<'ctx> { /// }; /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -511,7 +511,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -540,7 +540,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -572,7 +572,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -585,7 +585,7 @@ impl<'ctx> Builder<'ctx> { /// }; /// /// // link in the C++ type info for the `int` type - /// let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Generic), "_ZTIi"); + /// let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Zero), "_ZTIi"); /// type_info_int.set_linkage(Linkage::External); /// /// // make the catch landing pad @@ -607,7 +607,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -620,7 +620,7 @@ impl<'ctx> Builder<'ctx> { /// }; /// /// // link in the C++ type info for the `int` type - /// let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Generic), "_ZTIi"); + /// let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::Zero), "_ZTIi"); /// type_info_int.set_linkage(Linkage::External); /// /// // make the filter landing pad @@ -723,7 +723,7 @@ impl<'ctx> Builder<'ctx> { /// }; /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic); + /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -1473,7 +1473,7 @@ impl<'ctx> Builder<'ctx> { /// let f32_type = context.f32_type(); /// let i32_type = context.i32_type(); /// let arg_types = [i32_type.into()]; - /// let fn_type = void_type.fn_type(&arg_types, false).ptr_type(AddressSpace::Zero); + /// let fn_type = void_type.fn_type(&arg_types, false); /// let fn_value = module.add_function("bc", fn_type, None); /// let builder = context.create_builder(); /// let entry = context.append_basic_block(fn_value, "entry"); diff --git a/tests/all/test_passes.rs b/tests/all/test_passes.rs index bad66ef3a04..ea005fb78fe 100644 --- a/tests/all/test_passes.rs +++ b/tests/all/test_passes.rs @@ -165,11 +165,6 @@ fn test_pass_manager_builder() { pass_manager_builder.populate_module_pass_manager(&module_pass_manager); - #[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)); - #[cfg(not(feature = "llvm15-0"))] { let module2 = module.clone(); @@ -179,6 +174,11 @@ 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)); } #[test] From f944dd9c23d4184ee61cffbb720abb6445479d56 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 18 Dec 2022 22:56:47 +0100 Subject: [PATCH 29/34] Disable the kaleidoscope example for LLVM 15 (#2) --- .../implementation_typed_pointers.rs | 1200 ++++++++++++++++ examples/kaleidoscope/main.rs | 1203 +---------------- 2 files changed, 1212 insertions(+), 1191 deletions(-) create mode 100644 examples/kaleidoscope/implementation_typed_pointers.rs diff --git a/examples/kaleidoscope/implementation_typed_pointers.rs b/examples/kaleidoscope/implementation_typed_pointers.rs new file mode 100644 index 00000000000..3713f57def6 --- /dev/null +++ b/examples/kaleidoscope/implementation_typed_pointers.rs @@ -0,0 +1,1200 @@ +use std::borrow::Borrow; +use std::collections::HashMap; +use std::iter::Peekable; +use std::ops::DerefMut; +use std::str::Chars; + +use inkwell::builder::Builder; +use inkwell::context::Context; +use inkwell::module::Module; +use inkwell::passes::PassManager; +use inkwell::types::BasicMetadataTypeEnum; +use inkwell::values::{BasicMetadataValueEnum, FloatValue, FunctionValue, PointerValue}; +use inkwell::FloatPredicate; + +use crate::Token::*; + +const ANONYMOUS_FUNCTION_NAME: &str = "anonymous"; + +// ====================================================================================== +// LEXER ================================================================================ +// ====================================================================================== + +/// Represents a primitive syntax token. +#[derive(Debug, Clone)] +pub enum Token { + Binary, + Comma, + Comment, + Def, + Else, + EOF, + Extern, + For, + Ident(String), + If, + In, + LParen, + Number(f64), + Op(char), + RParen, + Then, + Unary, + Var, +} + +/// Defines an error encountered by the `Lexer`. +pub struct LexError { + pub error: &'static str, + pub index: usize, +} + +impl LexError { + #[allow(unused)] + pub fn new(msg: &'static str) -> LexError { + LexError { error: msg, index: 0 } + } + + #[allow(unused)] + pub fn with_index(msg: &'static str, index: usize) -> LexError { + LexError { error: msg, index } + } +} + +/// Defines the result of a lexing operation; namely a +/// `Token` on success, or a `LexError` on failure. +pub type LexResult = Result; + +/// Defines a lexer which transforms an input `String` into +/// a `Token` stream. +pub struct Lexer<'a> { + input: &'a str, + chars: Box>>, + pos: usize, +} + +impl<'a> Lexer<'a> { + /// Creates a new `Lexer`, given its source `input`. + pub fn new(input: &'a str) -> Lexer<'a> { + Lexer { + input, + chars: Box::new(input.chars().peekable()), + pos: 0, + } + } + + /// Lexes and returns the next `Token` from the source code. + pub fn lex(&mut self) -> LexResult { + let chars = self.chars.deref_mut(); + let src = self.input; + + let mut pos = self.pos; + + // Skip whitespaces + loop { + // Note: the following lines are in their own scope to + // limit how long 'chars' is borrowed, and in order to allow + // it to be borrowed again in the loop by 'chars.next()'. + { + let ch = chars.peek(); + + if ch.is_none() { + self.pos = pos; + + return Ok(Token::EOF); + } + + if !ch.unwrap().is_whitespace() { + break; + } + } + + chars.next(); + pos += 1; + } + + let start = pos; + let next = chars.next(); + + if next.is_none() { + return Ok(Token::EOF); + } + + pos += 1; + + // Actually get the next token. + let result = match next.unwrap() { + '(' => Ok(Token::LParen), + ')' => Ok(Token::RParen), + ',' => Ok(Token::Comma), + + '#' => { + // Comment + loop { + let ch = chars.next(); + pos += 1; + + if ch == Some('\n') { + break; + } + } + + Ok(Token::Comment) + }, + + '.' | '0'..='9' => { + // Parse number literal + loop { + let ch = match chars.peek() { + Some(ch) => *ch, + None => return Ok(Token::EOF), + }; + + // Parse float. + if ch != '.' && !ch.is_ascii_hexdigit() { + break; + } + + chars.next(); + pos += 1; + } + + Ok(Token::Number(src[start..pos].parse().unwrap())) + }, + + 'a'..='z' | 'A'..='Z' | '_' => { + // Parse identifier + loop { + let ch = match chars.peek() { + Some(ch) => *ch, + None => return Ok(Token::EOF), + }; + + // A word-like identifier only contains underscores and alphanumeric characters. + if ch != '_' && !ch.is_alphanumeric() { + break; + } + + chars.next(); + pos += 1; + } + + match &src[start..pos] { + "def" => Ok(Token::Def), + "extern" => Ok(Token::Extern), + "if" => Ok(Token::If), + "then" => Ok(Token::Then), + "else" => Ok(Token::Else), + "for" => Ok(Token::For), + "in" => Ok(Token::In), + "unary" => Ok(Token::Unary), + "binary" => Ok(Token::Binary), + "var" => Ok(Token::Var), + + ident => Ok(Token::Ident(ident.to_string())), + } + }, + + op => { + // Parse operator + Ok(Token::Op(op)) + }, + }; + + // Update stored position, and return + self.pos = pos; + + result + } +} + +impl<'a> Iterator for Lexer<'a> { + type Item = Token; + + /// Lexes the next `Token` and returns it. + /// On EOF or failure, `None` will be returned. + fn next(&mut self) -> Option { + match self.lex() { + Ok(EOF) | Err(_) => None, + Ok(token) => Some(token), + } + } +} + +// ====================================================================================== +// PARSER =============================================================================== +// ====================================================================================== + +/// Defines a primitive expression. +#[derive(Debug)] +pub enum Expr { + Binary { + op: char, + left: Box, + right: Box, + }, + + Call { + fn_name: String, + args: Vec, + }, + + Conditional { + cond: Box, + consequence: Box, + alternative: Box, + }, + + For { + var_name: String, + start: Box, + end: Box, + step: Option>, + body: Box, + }, + + Number(f64), + + Variable(String), + + VarIn { + variables: Vec<(String, Option)>, + body: Box, + }, +} + +/// Defines the prototype (name and parameters) of a function. +#[derive(Debug)] +pub struct Prototype { + pub name: String, + pub args: Vec, + pub is_op: bool, + pub prec: usize, +} + +/// Defines a user-defined or external function. +#[derive(Debug)] +pub struct Function { + pub prototype: Prototype, + pub body: Option, + pub is_anon: bool, +} + +/// Represents the `Expr` parser. +pub struct Parser<'a> { + tokens: Vec, + pos: usize, + prec: &'a mut HashMap, +} + +// I'm ignoring the 'must_use' lint in order to call 'self.advance' without checking +// the result when an EOF is acceptable. +#[allow(unused_must_use)] +impl<'a> Parser<'a> { + /// Creates a new parser, given an input `str` and a `HashMap` binding + /// an operator and its precedence in binary expressions. + pub fn new(input: String, op_precedence: &'a mut HashMap) -> Self { + let mut lexer = Lexer::new(input.as_str()); + let tokens = lexer.by_ref().collect(); + + Parser { + tokens, + prec: op_precedence, + pos: 0, + } + } + + /// Parses the content of the parser. + pub fn parse(&mut self) -> Result { + let result = match self.current()? { + Def => self.parse_def(), + Extern => self.parse_extern(), + _ => self.parse_toplevel_expr(), + }; + + match result { + Ok(result) => { + if !self.at_end() { + Err("Unexpected token after parsed expression.") + } else { + Ok(result) + } + }, + + err => err, + } + } + + /// Returns the current `Token`, without performing safety checks beforehand. + fn curr(&self) -> Token { + self.tokens[self.pos].clone() + } + + /// Returns the current `Token`, or an error that + /// indicates that the end of the file has been unexpectedly reached if it is the case. + fn current(&self) -> Result { + if self.pos >= self.tokens.len() { + Err("Unexpected end of file.") + } else { + Ok(self.tokens[self.pos].clone()) + } + } + + /// Advances the position, and returns an empty `Result` whose error + /// indicates that the end of the file has been unexpectedly reached. + /// This allows to use the `self.advance()?;` syntax. + fn advance(&mut self) -> Result<(), &'static str> { + let npos = self.pos + 1; + + self.pos = npos; + + if npos < self.tokens.len() { + Ok(()) + } else { + Err("Unexpected end of file.") + } + } + + /// Returns a value indicating whether or not the `Parser` + /// has reached the end of the input. + fn at_end(&self) -> bool { + self.pos >= self.tokens.len() + } + + /// Returns the precedence of the current `Token`, or 0 if it is not recognized as a binary operator. + fn get_tok_precedence(&self) -> i32 { + if let Ok(Op(op)) = self.current() { + *self.prec.get(&op).unwrap_or(&100) + } else { + -1 + } + } + + /// Parses the prototype of a function, whether external or user-defined. + fn parse_prototype(&mut self) -> Result { + let (id, is_operator, precedence) = match self.curr() { + Ident(id) => { + self.advance()?; + + (id, false, 0) + }, + + Binary => { + self.advance()?; + + let op = match self.curr() { + Op(ch) => ch, + _ => return Err("Expected operator in custom operator declaration."), + }; + + self.advance()?; + + let mut name = String::from("binary"); + + name.push(op); + + let prec = if let Number(prec) = self.curr() { + self.advance()?; + + prec as usize + } else { + 0 + }; + + self.prec.insert(op, prec as i32); + + (name, true, prec) + }, + + Unary => { + self.advance()?; + + let op = match self.curr() { + Op(ch) => ch, + _ => return Err("Expected operator in custom operator declaration."), + }; + + let mut name = String::from("unary"); + + name.push(op); + + self.advance()?; + + (name, true, 0) + }, + + _ => return Err("Expected identifier in prototype declaration."), + }; + + match self.curr() { + LParen => (), + _ => return Err("Expected '(' character in prototype declaration."), + } + + self.advance()?; + + if let RParen = self.curr() { + self.advance(); + + return Ok(Prototype { + name: id, + args: vec![], + is_op: is_operator, + prec: precedence, + }); + } + + let mut args = vec![]; + + loop { + match self.curr() { + Ident(name) => args.push(name), + _ => return Err("Expected identifier in parameter declaration."), + } + + self.advance()?; + + match self.curr() { + RParen => { + self.advance(); + break; + }, + Comma => { + self.advance(); + }, + _ => return Err("Expected ',' or ')' character in prototype declaration."), + } + } + + Ok(Prototype { + name: id, + args, + is_op: is_operator, + prec: precedence, + }) + } + + /// Parses a user-defined function. + fn parse_def(&mut self) -> Result { + // Eat 'def' keyword + self.pos += 1; + + // Parse signature of function + let proto = self.parse_prototype()?; + + // Parse body of function + let body = self.parse_expr()?; + + // Return new function + Ok(Function { + prototype: proto, + body: Some(body), + is_anon: false, + }) + } + + /// Parses an external function declaration. + fn parse_extern(&mut self) -> Result { + // Eat 'extern' keyword + self.pos += 1; + + // Parse signature of extern function + let proto = self.parse_prototype()?; + + Ok(Function { + prototype: proto, + body: None, + is_anon: false, + }) + } + + /// Parses any expression. + fn parse_expr(&mut self) -> Result { + match self.parse_unary_expr() { + Ok(left) => self.parse_binary_expr(0, left), + err => err, + } + } + + /// Parses a literal number. + fn parse_nb_expr(&mut self) -> Result { + // Simply convert Token::Number to Expr::Number + match self.curr() { + Number(nb) => { + self.advance(); + Ok(Expr::Number(nb)) + }, + _ => Err("Expected number literal."), + } + } + + /// Parses an expression enclosed in parenthesis. + fn parse_paren_expr(&mut self) -> Result { + match self.current()? { + LParen => (), + _ => return Err("Expected '(' character at start of parenthesized expression."), + } + + self.advance()?; + + let expr = self.parse_expr()?; + + match self.current()? { + RParen => (), + _ => return Err("Expected ')' character at end of parenthesized expression."), + } + + self.advance(); + + Ok(expr) + } + + /// Parses an expression that starts with an identifier (either a variable or a function call). + fn parse_id_expr(&mut self) -> Result { + let id = match self.curr() { + Ident(id) => id, + _ => return Err("Expected identifier."), + }; + + if self.advance().is_err() { + return Ok(Expr::Variable(id)); + } + + match self.curr() { + LParen => { + self.advance()?; + + if let RParen = self.curr() { + return Ok(Expr::Call { + fn_name: id, + args: vec![], + }); + } + + let mut args = vec![]; + + loop { + args.push(self.parse_expr()?); + + match self.current()? { + Comma => (), + RParen => break, + _ => return Err("Expected ',' character in function call."), + } + + self.advance()?; + } + + self.advance(); + + Ok(Expr::Call { fn_name: id, args }) + }, + + _ => Ok(Expr::Variable(id)), + } + } + + /// Parses an unary expression. + fn parse_unary_expr(&mut self) -> Result { + let op = match self.current()? { + Op(ch) => { + self.advance()?; + ch + }, + _ => return self.parse_primary(), + }; + + let mut name = String::from("unary"); + + name.push(op); + + Ok(Expr::Call { + fn_name: name, + args: vec![self.parse_unary_expr()?], + }) + } + + /// Parses a binary expression, given its left-hand expression. + fn parse_binary_expr(&mut self, prec: i32, mut left: Expr) -> Result { + loop { + let curr_prec = self.get_tok_precedence(); + + if curr_prec < prec || self.at_end() { + return Ok(left); + } + + let op = match self.curr() { + Op(op) => op, + _ => return Err("Invalid operator."), + }; + + self.advance()?; + + let mut right = self.parse_unary_expr()?; + + let next_prec = self.get_tok_precedence(); + + if curr_prec < next_prec { + right = self.parse_binary_expr(curr_prec + 1, right)?; + } + + left = Expr::Binary { + op, + left: Box::new(left), + right: Box::new(right), + }; + } + } + + /// Parses a conditional if..then..else expression. + fn parse_conditional_expr(&mut self) -> Result { + // eat 'if' token + self.advance()?; + + let cond = self.parse_expr()?; + + // eat 'then' token + match self.current() { + Ok(Then) => self.advance()?, + _ => return Err("Expected 'then' keyword."), + } + + let then = self.parse_expr()?; + + // eat 'else' token + match self.current() { + Ok(Else) => self.advance()?, + _ => return Err("Expected 'else' keyword."), + } + + let otherwise = self.parse_expr()?; + + Ok(Expr::Conditional { + cond: Box::new(cond), + consequence: Box::new(then), + alternative: Box::new(otherwise), + }) + } + + /// Parses a loop for..in.. expression. + fn parse_for_expr(&mut self) -> Result { + // eat 'for' token + self.advance()?; + + let name = match self.curr() { + Ident(n) => n, + _ => return Err("Expected identifier in for loop."), + }; + + // eat identifier + self.advance()?; + + // eat '=' token + match self.curr() { + Op('=') => self.advance()?, + _ => return Err("Expected '=' character in for loop."), + } + + let start = self.parse_expr()?; + + // eat ',' token + match self.current()? { + Comma => self.advance()?, + _ => return Err("Expected ',' character in for loop."), + } + + let end = self.parse_expr()?; + + // parse (optional) step expression + let step = match self.current()? { + Comma => { + self.advance()?; + + Some(self.parse_expr()?) + }, + + _ => None, + }; + + // eat 'in' token + match self.current()? { + In => self.advance()?, + _ => return Err("Expected 'in' keyword in for loop."), + } + + let body = self.parse_expr()?; + + Ok(Expr::For { + var_name: name, + start: Box::new(start), + end: Box::new(end), + step: step.map(Box::new), + body: Box::new(body), + }) + } + + /// Parses a var..in expression. + fn parse_var_expr(&mut self) -> Result { + // eat 'var' token + self.advance()?; + + let mut variables = Vec::new(); + + // parse variables + loop { + let name = match self.curr() { + Ident(name) => name, + _ => return Err("Expected identifier in 'var..in' declaration."), + }; + + self.advance()?; + + // read (optional) initializer + let initializer = match self.curr() { + Op('=') => Some({ + self.advance()?; + self.parse_expr()? + }), + + _ => None, + }; + + variables.push((name, initializer)); + + match self.curr() { + Comma => { + self.advance()?; + }, + In => { + self.advance()?; + break; + }, + _ => return Err("Expected comma or 'in' keyword in variable declaration."), + } + } + + // parse body + let body = self.parse_expr()?; + + Ok(Expr::VarIn { + variables, + body: Box::new(body), + }) + } + + /// Parses a primary expression (an identifier, a number or a parenthesized expression). + fn parse_primary(&mut self) -> Result { + match self.curr() { + Ident(_) => self.parse_id_expr(), + Number(_) => self.parse_nb_expr(), + LParen => self.parse_paren_expr(), + If => self.parse_conditional_expr(), + For => self.parse_for_expr(), + Var => self.parse_var_expr(), + _ => Err("Unknown expression."), + } + } + + /// Parses a top-level expression and makes an anonymous function out of it, + /// for easier compilation. + fn parse_toplevel_expr(&mut self) -> Result { + match self.parse_expr() { + Ok(expr) => Ok(Function { + prototype: Prototype { + name: ANONYMOUS_FUNCTION_NAME.to_string(), + args: vec![], + is_op: false, + prec: 0, + }, + body: Some(expr), + is_anon: true, + }), + + Err(err) => Err(err), + } + } +} + +// ====================================================================================== +// COMPILER ============================================================================= +// ====================================================================================== + +/// Defines the `Expr` compiler. +pub struct Compiler<'a, 'ctx> { + pub context: &'ctx Context, + pub builder: &'a Builder<'ctx>, + pub fpm: &'a PassManager>, + pub module: &'a Module<'ctx>, + pub function: &'a Function, + + variables: HashMap>, + fn_value_opt: Option>, +} + +impl<'a, 'ctx> Compiler<'a, 'ctx> { + /// Gets a defined function given its name. + #[inline] + fn get_function(&self, name: &str) -> Option> { + self.module.get_function(name) + } + + /// Returns the `FunctionValue` representing the function being compiled. + #[inline] + fn fn_value(&self) -> FunctionValue<'ctx> { + self.fn_value_opt.unwrap() + } + + /// Creates a new stack allocation instruction in the entry block of the function. + fn create_entry_block_alloca(&self, name: &str) -> PointerValue<'ctx> { + let builder = self.context.create_builder(); + + let entry = self.fn_value().get_first_basic_block().unwrap(); + + match entry.get_first_instruction() { + Some(first_instr) => builder.position_before(&first_instr), + None => builder.position_at_end(entry), + } + + builder.build_alloca(self.context.f64_type(), name) + } + + /// Compiles the specified `Expr` into an LLVM `FloatValue`. + fn compile_expr(&mut self, expr: &Expr) -> Result, &'static str> { + match *expr { + Expr::Number(nb) => Ok(self.context.f64_type().const_float(nb)), + + Expr::Variable(ref name) => match self.variables.get(name.as_str()) { + Some(var) => Ok(self.builder.build_load(*var, name.as_str()).into_float_value()), + None => Err("Could not find a matching variable."), + }, + + Expr::VarIn { + ref variables, + ref body, + } => { + let mut old_bindings = Vec::new(); + + for &(ref var_name, ref initializer) in variables { + let var_name = var_name.as_str(); + + let initial_val = match *initializer { + Some(ref init) => self.compile_expr(init)?, + None => self.context.f64_type().const_float(0.), + }; + + let alloca = self.create_entry_block_alloca(var_name); + + self.builder.build_store(alloca, initial_val); + + if let Some(old_binding) = self.variables.remove(var_name) { + old_bindings.push(old_binding); + } + + self.variables.insert(var_name.to_string(), alloca); + } + + let body = self.compile_expr(body)?; + + for binding in old_bindings { + self.variables + .insert(binding.get_name().to_str().unwrap().to_string(), binding); + } + + Ok(body) + }, + + Expr::Binary { + op, + ref left, + ref right, + } => { + if op == '=' { + // handle assignement + let var_name = match *left.borrow() { + Expr::Variable(ref var_name) => var_name, + _ => { + return Err("Expected variable as left-hand operator of assignement."); + }, + }; + + let var_val = self.compile_expr(right)?; + let var = self.variables.get(var_name.as_str()).ok_or("Undefined variable.")?; + + self.builder.build_store(*var, var_val); + + Ok(var_val) + } else { + let lhs = self.compile_expr(left)?; + let rhs = self.compile_expr(right)?; + + match op { + '+' => Ok(self.builder.build_float_add(lhs, rhs, "tmpadd")), + '-' => Ok(self.builder.build_float_sub(lhs, rhs, "tmpsub")), + '*' => Ok(self.builder.build_float_mul(lhs, rhs, "tmpmul")), + '/' => Ok(self.builder.build_float_div(lhs, rhs, "tmpdiv")), + '<' => Ok({ + let cmp = self + .builder + .build_float_compare(FloatPredicate::ULT, lhs, rhs, "tmpcmp"); + + self.builder + .build_unsigned_int_to_float(cmp, self.context.f64_type(), "tmpbool") + }), + '>' => Ok({ + let cmp = self + .builder + .build_float_compare(FloatPredicate::ULT, rhs, lhs, "tmpcmp"); + + self.builder + .build_unsigned_int_to_float(cmp, self.context.f64_type(), "tmpbool") + }), + + custom => { + let mut name = String::from("binary"); + + name.push(custom); + + match self.get_function(name.as_str()) { + Some(fun) => { + match self + .builder + .build_call(fun, &[lhs.into(), rhs.into()], "tmpbin") + .try_as_basic_value() + .left() + { + Some(value) => Ok(value.into_float_value()), + None => Err("Invalid call produced."), + } + }, + + None => Err("Undefined binary operator."), + } + }, + } + } + }, + + Expr::Call { ref fn_name, ref args } => match self.get_function(fn_name.as_str()) { + Some(fun) => { + let mut compiled_args = Vec::with_capacity(args.len()); + + for arg in args { + compiled_args.push(self.compile_expr(arg)?); + } + + let argsv: Vec = + compiled_args.iter().by_ref().map(|&val| val.into()).collect(); + + match self + .builder + .build_call(fun, argsv.as_slice(), "tmp") + .try_as_basic_value() + .left() + { + Some(value) => Ok(value.into_float_value()), + None => Err("Invalid call produced."), + } + }, + None => Err("Unknown function."), + }, + + Expr::Conditional { + ref cond, + ref consequence, + ref alternative, + } => { + let parent = self.fn_value(); + let zero_const = self.context.f64_type().const_float(0.0); + + // create condition by comparing without 0.0 and returning an int + let cond = self.compile_expr(cond)?; + let cond = self + .builder + .build_float_compare(FloatPredicate::ONE, cond, zero_const, "ifcond"); + + // build branch + let then_bb = self.context.append_basic_block(parent, "then"); + let else_bb = self.context.append_basic_block(parent, "else"); + let cont_bb = self.context.append_basic_block(parent, "ifcont"); + + self.builder.build_conditional_branch(cond, then_bb, else_bb); + + // build then block + self.builder.position_at_end(then_bb); + let then_val = self.compile_expr(consequence)?; + self.builder.build_unconditional_branch(cont_bb); + + let then_bb = self.builder.get_insert_block().unwrap(); + + // build else block + self.builder.position_at_end(else_bb); + let else_val = self.compile_expr(alternative)?; + self.builder.build_unconditional_branch(cont_bb); + + let else_bb = self.builder.get_insert_block().unwrap(); + + // emit merge block + self.builder.position_at_end(cont_bb); + + let phi = self.builder.build_phi(self.context.f64_type(), "iftmp"); + + phi.add_incoming(&[(&then_val, then_bb), (&else_val, else_bb)]); + + Ok(phi.as_basic_value().into_float_value()) + }, + + Expr::For { + ref var_name, + ref start, + ref end, + ref step, + ref body, + } => { + let parent = self.fn_value(); + + let start_alloca = self.create_entry_block_alloca(var_name); + let start = self.compile_expr(start)?; + + self.builder.build_store(start_alloca, start); + + // go from current block to loop block + let loop_bb = self.context.append_basic_block(parent, "loop"); + + self.builder.build_unconditional_branch(loop_bb); + self.builder.position_at_end(loop_bb); + + let old_val = self.variables.remove(var_name.as_str()); + + self.variables.insert(var_name.to_owned(), start_alloca); + + // emit body + self.compile_expr(body)?; + + // emit step + let step = match *step { + Some(ref step) => self.compile_expr(step)?, + None => self.context.f64_type().const_float(1.0), + }; + + // compile end condition + let end_cond = self.compile_expr(end)?; + + let curr_var = self.builder.build_load(start_alloca, var_name); + let next_var = self + .builder + .build_float_add(curr_var.into_float_value(), step, "nextvar"); + + self.builder.build_store(start_alloca, next_var); + + let end_cond = self.builder.build_float_compare( + FloatPredicate::ONE, + end_cond, + self.context.f64_type().const_float(0.0), + "loopcond", + ); + let after_bb = self.context.append_basic_block(parent, "afterloop"); + + self.builder.build_conditional_branch(end_cond, loop_bb, after_bb); + self.builder.position_at_end(after_bb); + + self.variables.remove(var_name); + + if let Some(val) = old_val { + self.variables.insert(var_name.to_owned(), val); + } + + Ok(self.context.f64_type().const_float(0.0)) + }, + } + } + + /// 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()) + .map(|f| f.into()) + .collect::>(); + let args_types = args_types.as_slice(); + + let fn_type = self.context.f64_type().fn_type(args_types, false); + let fn_val = self.module.add_function(proto.name.as_str(), fn_type, None); + + // set arguments names + for (i, arg) in fn_val.get_param_iter().enumerate() { + arg.into_float_value().set_name(proto.args[i].as_str()); + } + + // finally return built prototype + Ok(fn_val) + } + + /// Compiles the specified `Function` into an LLVM `FunctionValue`. + fn compile_fn(&mut self) -> Result, &'static str> { + let proto = &self.function.prototype; + let function = self.compile_prototype(proto)?; + + // got external function, returning only compiled prototype + if self.function.body.is_none() { + return Ok(function); + } + + let entry = self.context.append_basic_block(function, "entry"); + + self.builder.position_at_end(entry); + + // update fn field + self.fn_value_opt = Some(function); + + // build variables map + self.variables.reserve(proto.args.len()); + + for (i, arg) in function.get_param_iter().enumerate() { + let arg_name = proto.args[i].as_str(); + let alloca = self.create_entry_block_alloca(arg_name); + + self.builder.build_store(alloca, arg); + + self.variables.insert(proto.args[i].clone(), alloca); + } + + // compile body + let body = self.compile_expr(self.function.body.as_ref().unwrap())?; + + self.builder.build_return(Some(&body)); + + // return the whole thing after verification and optimization + if function.verify(true) { + self.fpm.run_on(&function); + + Ok(function) + } else { + unsafe { + function.delete(); + } + + Err("Invalid generated function.") + } + } + + /// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`. + pub fn compile( + context: &'ctx Context, + builder: &'a Builder<'ctx>, + pass_manager: &'a PassManager>, + module: &'a Module<'ctx>, + function: &Function, + ) -> Result, &'static str> { + let mut compiler = Compiler { + context, + builder, + fpm: pass_manager, + module, + function, + fn_value_opt: None, + variables: HashMap::new(), + }; + + compiler.compile_fn() + } +} diff --git a/examples/kaleidoscope/main.rs b/examples/kaleidoscope/main.rs index e64d976ce00..3243dc3a258 100644 --- a/examples/kaleidoscope/main.rs +++ b/examples/kaleidoscope/main.rs @@ -12,1205 +12,20 @@ //! Both the `Parser` and the `Compiler` may fail, in which case they would return //! an error represented by `Result`, for easier error reporting. -use std::borrow::Borrow; use std::collections::HashMap; use std::io::{self, Write}; -use std::iter::Peekable; -use std::ops::DerefMut; -use std::str::Chars; -use inkwell::builder::Builder; use inkwell::context::Context; -use inkwell::module::Module; use inkwell::passes::PassManager; -use inkwell::types::BasicMetadataTypeEnum; -use inkwell::values::{BasicMetadataValueEnum, FloatValue, FunctionValue, PointerValue}; -use inkwell::{FloatPredicate, OptimizationLevel}; +use inkwell::OptimizationLevel; -use crate::Token::*; +use inkwell_internals::llvm_versions; -const ANONYMOUS_FUNCTION_NAME: &str = "anonymous"; +#[cfg(not(any(feature = "llvm15-0")))] +mod implementation_typed_pointers; -// ====================================================================================== -// LEXER ================================================================================ -// ====================================================================================== - -/// Represents a primitive syntax token. -#[derive(Debug, Clone)] -pub enum Token { - Binary, - Comma, - Comment, - Def, - Else, - EOF, - Extern, - For, - Ident(String), - If, - In, - LParen, - Number(f64), - Op(char), - RParen, - Then, - Unary, - Var, -} - -/// Defines an error encountered by the `Lexer`. -pub struct LexError { - pub error: &'static str, - pub index: usize, -} - -impl LexError { - pub fn new(msg: &'static str) -> LexError { - LexError { error: msg, index: 0 } - } - - pub fn with_index(msg: &'static str, index: usize) -> LexError { - LexError { error: msg, index } - } -} - -/// Defines the result of a lexing operation; namely a -/// `Token` on success, or a `LexError` on failure. -pub type LexResult = Result; - -/// Defines a lexer which transforms an input `String` into -/// a `Token` stream. -pub struct Lexer<'a> { - input: &'a str, - chars: Box>>, - pos: usize, -} - -impl<'a> Lexer<'a> { - /// Creates a new `Lexer`, given its source `input`. - pub fn new(input: &'a str) -> Lexer<'a> { - Lexer { - input, - chars: Box::new(input.chars().peekable()), - pos: 0, - } - } - - /// Lexes and returns the next `Token` from the source code. - pub fn lex(&mut self) -> LexResult { - let chars = self.chars.deref_mut(); - let src = self.input; - - let mut pos = self.pos; - - // Skip whitespaces - loop { - // Note: the following lines are in their own scope to - // limit how long 'chars' is borrowed, and in order to allow - // it to be borrowed again in the loop by 'chars.next()'. - { - let ch = chars.peek(); - - if ch.is_none() { - self.pos = pos; - - return Ok(Token::EOF); - } - - if !ch.unwrap().is_whitespace() { - break; - } - } - - chars.next(); - pos += 1; - } - - let start = pos; - let next = chars.next(); - - if next.is_none() { - return Ok(Token::EOF); - } - - pos += 1; - - // Actually get the next token. - let result = match next.unwrap() { - '(' => Ok(Token::LParen), - ')' => Ok(Token::RParen), - ',' => Ok(Token::Comma), - - '#' => { - // Comment - loop { - let ch = chars.next(); - pos += 1; - - if ch == Some('\n') { - break; - } - } - - Ok(Token::Comment) - }, - - '.' | '0'..='9' => { - // Parse number literal - loop { - let ch = match chars.peek() { - Some(ch) => *ch, - None => return Ok(Token::EOF), - }; - - // Parse float. - if ch != '.' && !ch.is_ascii_hexdigit() { - break; - } - - chars.next(); - pos += 1; - } - - Ok(Token::Number(src[start..pos].parse().unwrap())) - }, - - 'a'..='z' | 'A'..='Z' | '_' => { - // Parse identifier - loop { - let ch = match chars.peek() { - Some(ch) => *ch, - None => return Ok(Token::EOF), - }; - - // A word-like identifier only contains underscores and alphanumeric characters. - if ch != '_' && !ch.is_alphanumeric() { - break; - } - - chars.next(); - pos += 1; - } - - match &src[start..pos] { - "def" => Ok(Token::Def), - "extern" => Ok(Token::Extern), - "if" => Ok(Token::If), - "then" => Ok(Token::Then), - "else" => Ok(Token::Else), - "for" => Ok(Token::For), - "in" => Ok(Token::In), - "unary" => Ok(Token::Unary), - "binary" => Ok(Token::Binary), - "var" => Ok(Token::Var), - - ident => Ok(Token::Ident(ident.to_string())), - } - }, - - op => { - // Parse operator - Ok(Token::Op(op)) - }, - }; - - // Update stored position, and return - self.pos = pos; - - result - } -} - -impl<'a> Iterator for Lexer<'a> { - type Item = Token; - - /// Lexes the next `Token` and returns it. - /// On EOF or failure, `None` will be returned. - fn next(&mut self) -> Option { - match self.lex() { - Ok(EOF) | Err(_) => None, - Ok(token) => Some(token), - } - } -} - -// ====================================================================================== -// PARSER =============================================================================== -// ====================================================================================== - -/// Defines a primitive expression. -#[derive(Debug)] -pub enum Expr { - Binary { - op: char, - left: Box, - right: Box, - }, - - Call { - fn_name: String, - args: Vec, - }, - - Conditional { - cond: Box, - consequence: Box, - alternative: Box, - }, - - For { - var_name: String, - start: Box, - end: Box, - step: Option>, - body: Box, - }, - - Number(f64), - - Variable(String), - - VarIn { - variables: Vec<(String, Option)>, - body: Box, - }, -} - -/// Defines the prototype (name and parameters) of a function. -#[derive(Debug)] -pub struct Prototype { - pub name: String, - pub args: Vec, - pub is_op: bool, - pub prec: usize, -} - -/// Defines a user-defined or external function. -#[derive(Debug)] -pub struct Function { - pub prototype: Prototype, - pub body: Option, - pub is_anon: bool, -} - -/// Represents the `Expr` parser. -pub struct Parser<'a> { - tokens: Vec, - pos: usize, - prec: &'a mut HashMap, -} - -// I'm ignoring the 'must_use' lint in order to call 'self.advance' without checking -// the result when an EOF is acceptable. -#[allow(unused_must_use)] -impl<'a> Parser<'a> { - /// Creates a new parser, given an input `str` and a `HashMap` binding - /// an operator and its precedence in binary expressions. - pub fn new(input: String, op_precedence: &'a mut HashMap) -> Self { - let mut lexer = Lexer::new(input.as_str()); - let tokens = lexer.by_ref().collect(); - - Parser { - tokens, - prec: op_precedence, - pos: 0, - } - } - - /// Parses the content of the parser. - pub fn parse(&mut self) -> Result { - let result = match self.current()? { - Def => self.parse_def(), - Extern => self.parse_extern(), - _ => self.parse_toplevel_expr(), - }; - - match result { - Ok(result) => { - if !self.at_end() { - Err("Unexpected token after parsed expression.") - } else { - Ok(result) - } - }, - - err => err, - } - } - - /// Returns the current `Token`, without performing safety checks beforehand. - fn curr(&self) -> Token { - self.tokens[self.pos].clone() - } - - /// Returns the current `Token`, or an error that - /// indicates that the end of the file has been unexpectedly reached if it is the case. - fn current(&self) -> Result { - if self.pos >= self.tokens.len() { - Err("Unexpected end of file.") - } else { - Ok(self.tokens[self.pos].clone()) - } - } - - /// Advances the position, and returns an empty `Result` whose error - /// indicates that the end of the file has been unexpectedly reached. - /// This allows to use the `self.advance()?;` syntax. - fn advance(&mut self) -> Result<(), &'static str> { - let npos = self.pos + 1; - - self.pos = npos; - - if npos < self.tokens.len() { - Ok(()) - } else { - Err("Unexpected end of file.") - } - } - - /// Returns a value indicating whether or not the `Parser` - /// has reached the end of the input. - fn at_end(&self) -> bool { - self.pos >= self.tokens.len() - } - - /// Returns the precedence of the current `Token`, or 0 if it is not recognized as a binary operator. - fn get_tok_precedence(&self) -> i32 { - if let Ok(Op(op)) = self.current() { - *self.prec.get(&op).unwrap_or(&100) - } else { - -1 - } - } - - /// Parses the prototype of a function, whether external or user-defined. - fn parse_prototype(&mut self) -> Result { - let (id, is_operator, precedence) = match self.curr() { - Ident(id) => { - self.advance()?; - - (id, false, 0) - }, - - Binary => { - self.advance()?; - - let op = match self.curr() { - Op(ch) => ch, - _ => return Err("Expected operator in custom operator declaration."), - }; - - self.advance()?; - - let mut name = String::from("binary"); - - name.push(op); - - let prec = if let Number(prec) = self.curr() { - self.advance()?; - - prec as usize - } else { - 0 - }; - - self.prec.insert(op, prec as i32); - - (name, true, prec) - }, - - Unary => { - self.advance()?; - - let op = match self.curr() { - Op(ch) => ch, - _ => return Err("Expected operator in custom operator declaration."), - }; - - let mut name = String::from("unary"); - - name.push(op); - - self.advance()?; - - (name, true, 0) - }, - - _ => return Err("Expected identifier in prototype declaration."), - }; - - match self.curr() { - LParen => (), - _ => return Err("Expected '(' character in prototype declaration."), - } - - self.advance()?; - - if let RParen = self.curr() { - self.advance(); - - return Ok(Prototype { - name: id, - args: vec![], - is_op: is_operator, - prec: precedence, - }); - } - - let mut args = vec![]; - - loop { - match self.curr() { - Ident(name) => args.push(name), - _ => return Err("Expected identifier in parameter declaration."), - } - - self.advance()?; - - match self.curr() { - RParen => { - self.advance(); - break; - }, - Comma => { - self.advance(); - }, - _ => return Err("Expected ',' or ')' character in prototype declaration."), - } - } - - Ok(Prototype { - name: id, - args, - is_op: is_operator, - prec: precedence, - }) - } - - /// Parses a user-defined function. - fn parse_def(&mut self) -> Result { - // Eat 'def' keyword - self.pos += 1; - - // Parse signature of function - let proto = self.parse_prototype()?; - - // Parse body of function - let body = self.parse_expr()?; - - // Return new function - Ok(Function { - prototype: proto, - body: Some(body), - is_anon: false, - }) - } - - /// Parses an external function declaration. - fn parse_extern(&mut self) -> Result { - // Eat 'extern' keyword - self.pos += 1; - - // Parse signature of extern function - let proto = self.parse_prototype()?; - - Ok(Function { - prototype: proto, - body: None, - is_anon: false, - }) - } - - /// Parses any expression. - fn parse_expr(&mut self) -> Result { - match self.parse_unary_expr() { - Ok(left) => self.parse_binary_expr(0, left), - err => err, - } - } - - /// Parses a literal number. - fn parse_nb_expr(&mut self) -> Result { - // Simply convert Token::Number to Expr::Number - match self.curr() { - Number(nb) => { - self.advance(); - Ok(Expr::Number(nb)) - }, - _ => Err("Expected number literal."), - } - } - - /// Parses an expression enclosed in parenthesis. - fn parse_paren_expr(&mut self) -> Result { - match self.current()? { - LParen => (), - _ => return Err("Expected '(' character at start of parenthesized expression."), - } - - self.advance()?; - - let expr = self.parse_expr()?; - - match self.current()? { - RParen => (), - _ => return Err("Expected ')' character at end of parenthesized expression."), - } - - self.advance(); - - Ok(expr) - } - - /// Parses an expression that starts with an identifier (either a variable or a function call). - fn parse_id_expr(&mut self) -> Result { - let id = match self.curr() { - Ident(id) => id, - _ => return Err("Expected identifier."), - }; - - if self.advance().is_err() { - return Ok(Expr::Variable(id)); - } - - match self.curr() { - LParen => { - self.advance()?; - - if let RParen = self.curr() { - return Ok(Expr::Call { - fn_name: id, - args: vec![], - }); - } - - let mut args = vec![]; - - loop { - args.push(self.parse_expr()?); - - match self.current()? { - Comma => (), - RParen => break, - _ => return Err("Expected ',' character in function call."), - } - - self.advance()?; - } - - self.advance(); - - Ok(Expr::Call { fn_name: id, args }) - }, - - _ => Ok(Expr::Variable(id)), - } - } - - /// Parses an unary expression. - fn parse_unary_expr(&mut self) -> Result { - let op = match self.current()? { - Op(ch) => { - self.advance()?; - ch - }, - _ => return self.parse_primary(), - }; - - let mut name = String::from("unary"); - - name.push(op); - - Ok(Expr::Call { - fn_name: name, - args: vec![self.parse_unary_expr()?], - }) - } - - /// Parses a binary expression, given its left-hand expression. - fn parse_binary_expr(&mut self, prec: i32, mut left: Expr) -> Result { - loop { - let curr_prec = self.get_tok_precedence(); - - if curr_prec < prec || self.at_end() { - return Ok(left); - } - - let op = match self.curr() { - Op(op) => op, - _ => return Err("Invalid operator."), - }; - - self.advance()?; - - let mut right = self.parse_unary_expr()?; - - let next_prec = self.get_tok_precedence(); - - if curr_prec < next_prec { - right = self.parse_binary_expr(curr_prec + 1, right)?; - } - - left = Expr::Binary { - op, - left: Box::new(left), - right: Box::new(right), - }; - } - } - - /// Parses a conditional if..then..else expression. - fn parse_conditional_expr(&mut self) -> Result { - // eat 'if' token - self.advance()?; - - let cond = self.parse_expr()?; - - // eat 'then' token - match self.current() { - Ok(Then) => self.advance()?, - _ => return Err("Expected 'then' keyword."), - } - - let then = self.parse_expr()?; - - // eat 'else' token - match self.current() { - Ok(Else) => self.advance()?, - _ => return Err("Expected 'else' keyword."), - } - - let otherwise = self.parse_expr()?; - - Ok(Expr::Conditional { - cond: Box::new(cond), - consequence: Box::new(then), - alternative: Box::new(otherwise), - }) - } - - /// Parses a loop for..in.. expression. - fn parse_for_expr(&mut self) -> Result { - // eat 'for' token - self.advance()?; - - let name = match self.curr() { - Ident(n) => n, - _ => return Err("Expected identifier in for loop."), - }; - - // eat identifier - self.advance()?; - - // eat '=' token - match self.curr() { - Op('=') => self.advance()?, - _ => return Err("Expected '=' character in for loop."), - } - - let start = self.parse_expr()?; - - // eat ',' token - match self.current()? { - Comma => self.advance()?, - _ => return Err("Expected ',' character in for loop."), - } - - let end = self.parse_expr()?; - - // parse (optional) step expression - let step = match self.current()? { - Comma => { - self.advance()?; - - Some(self.parse_expr()?) - }, - - _ => None, - }; - - // eat 'in' token - match self.current()? { - In => self.advance()?, - _ => return Err("Expected 'in' keyword in for loop."), - } - - let body = self.parse_expr()?; - - Ok(Expr::For { - var_name: name, - start: Box::new(start), - end: Box::new(end), - step: step.map(Box::new), - body: Box::new(body), - }) - } - - /// Parses a var..in expression. - fn parse_var_expr(&mut self) -> Result { - // eat 'var' token - self.advance()?; - - let mut variables = Vec::new(); - - // parse variables - loop { - let name = match self.curr() { - Ident(name) => name, - _ => return Err("Expected identifier in 'var..in' declaration."), - }; - - self.advance()?; - - // read (optional) initializer - let initializer = match self.curr() { - Op('=') => Some({ - self.advance()?; - self.parse_expr()? - }), - - _ => None, - }; - - variables.push((name, initializer)); - - match self.curr() { - Comma => { - self.advance()?; - }, - In => { - self.advance()?; - break; - }, - _ => return Err("Expected comma or 'in' keyword in variable declaration."), - } - } - - // parse body - let body = self.parse_expr()?; - - Ok(Expr::VarIn { - variables, - body: Box::new(body), - }) - } - - /// Parses a primary expression (an identifier, a number or a parenthesized expression). - fn parse_primary(&mut self) -> Result { - match self.curr() { - Ident(_) => self.parse_id_expr(), - Number(_) => self.parse_nb_expr(), - LParen => self.parse_paren_expr(), - If => self.parse_conditional_expr(), - For => self.parse_for_expr(), - Var => self.parse_var_expr(), - _ => Err("Unknown expression."), - } - } - - /// Parses a top-level expression and makes an anonymous function out of it, - /// for easier compilation. - fn parse_toplevel_expr(&mut self) -> Result { - match self.parse_expr() { - Ok(expr) => Ok(Function { - prototype: Prototype { - name: ANONYMOUS_FUNCTION_NAME.to_string(), - args: vec![], - is_op: false, - prec: 0, - }, - body: Some(expr), - is_anon: true, - }), - - Err(err) => Err(err), - } - } -} - -// ====================================================================================== -// COMPILER ============================================================================= -// ====================================================================================== - -/// Defines the `Expr` compiler. -pub struct Compiler<'a, 'ctx> { - pub context: &'ctx Context, - pub builder: &'a Builder<'ctx>, - pub fpm: &'a PassManager>, - pub module: &'a Module<'ctx>, - pub function: &'a Function, - - variables: HashMap>, - fn_value_opt: Option>, -} - -impl<'a, 'ctx> Compiler<'a, 'ctx> { - /// Gets a defined function given its name. - #[inline] - fn get_function(&self, name: &str) -> Option> { - self.module.get_function(name) - } - - /// Returns the `FunctionValue` representing the function being compiled. - #[inline] - fn fn_value(&self) -> FunctionValue<'ctx> { - self.fn_value_opt.unwrap() - } - - /// Creates a new stack allocation instruction in the entry block of the function. - fn create_entry_block_alloca(&self, name: &str) -> PointerValue<'ctx> { - let builder = self.context.create_builder(); - - let entry = self.fn_value().get_first_basic_block().unwrap(); - - match entry.get_first_instruction() { - Some(first_instr) => builder.position_before(&first_instr), - None => builder.position_at_end(entry), - } - - builder.build_alloca(self.context.f64_type(), name) - } - - /// Compiles the specified `Expr` into an LLVM `FloatValue`. - fn compile_expr(&mut self, expr: &Expr) -> Result, &'static str> { - match *expr { - Expr::Number(nb) => Ok(self.context.f64_type().const_float(nb)), - - Expr::Variable(ref name) => match self.variables.get(name.as_str()) { - Some(var) => Ok(self.builder.build_load(*var, name.as_str()).into_float_value()), - None => Err("Could not find a matching variable."), - }, - - Expr::VarIn { - ref variables, - ref body, - } => { - let mut old_bindings = Vec::new(); - - for &(ref var_name, ref initializer) in variables { - let var_name = var_name.as_str(); - - let initial_val = match *initializer { - Some(ref init) => self.compile_expr(init)?, - None => self.context.f64_type().const_float(0.), - }; - - let alloca = self.create_entry_block_alloca(var_name); - - self.builder.build_store(alloca, initial_val); - - if let Some(old_binding) = self.variables.remove(var_name) { - old_bindings.push(old_binding); - } - - self.variables.insert(var_name.to_string(), alloca); - } - - let body = self.compile_expr(body)?; - - for binding in old_bindings { - self.variables - .insert(binding.get_name().to_str().unwrap().to_string(), binding); - } - - Ok(body) - }, - - Expr::Binary { - op, - ref left, - ref right, - } => { - if op == '=' { - // handle assignement - let var_name = match *left.borrow() { - Expr::Variable(ref var_name) => var_name, - _ => { - return Err("Expected variable as left-hand operator of assignement."); - }, - }; - - let var_val = self.compile_expr(right)?; - let var = self.variables.get(var_name.as_str()).ok_or("Undefined variable.")?; - - self.builder.build_store(*var, var_val); - - Ok(var_val) - } else { - let lhs = self.compile_expr(left)?; - let rhs = self.compile_expr(right)?; - - match op { - '+' => Ok(self.builder.build_float_add(lhs, rhs, "tmpadd")), - '-' => Ok(self.builder.build_float_sub(lhs, rhs, "tmpsub")), - '*' => Ok(self.builder.build_float_mul(lhs, rhs, "tmpmul")), - '/' => Ok(self.builder.build_float_div(lhs, rhs, "tmpdiv")), - '<' => Ok({ - let cmp = self - .builder - .build_float_compare(FloatPredicate::ULT, lhs, rhs, "tmpcmp"); - - self.builder - .build_unsigned_int_to_float(cmp, self.context.f64_type(), "tmpbool") - }), - '>' => Ok({ - let cmp = self - .builder - .build_float_compare(FloatPredicate::ULT, rhs, lhs, "tmpcmp"); - - self.builder - .build_unsigned_int_to_float(cmp, self.context.f64_type(), "tmpbool") - }), - - custom => { - let mut name = String::from("binary"); - - name.push(custom); - - match self.get_function(name.as_str()) { - Some(fun) => { - match self - .builder - .build_call(fun, &[lhs.into(), rhs.into()], "tmpbin") - .try_as_basic_value() - .left() - { - Some(value) => Ok(value.into_float_value()), - None => Err("Invalid call produced."), - } - }, - - None => Err("Undefined binary operator."), - } - }, - } - } - }, - - Expr::Call { ref fn_name, ref args } => match self.get_function(fn_name.as_str()) { - Some(fun) => { - let mut compiled_args = Vec::with_capacity(args.len()); - - for arg in args { - compiled_args.push(self.compile_expr(arg)?); - } - - let argsv: Vec = - compiled_args.iter().by_ref().map(|&val| val.into()).collect(); - - match self - .builder - .build_call(fun, argsv.as_slice(), "tmp") - .try_as_basic_value() - .left() - { - Some(value) => Ok(value.into_float_value()), - None => Err("Invalid call produced."), - } - }, - None => Err("Unknown function."), - }, - - Expr::Conditional { - ref cond, - ref consequence, - ref alternative, - } => { - let parent = self.fn_value(); - let zero_const = self.context.f64_type().const_float(0.0); - - // create condition by comparing without 0.0 and returning an int - let cond = self.compile_expr(cond)?; - let cond = self - .builder - .build_float_compare(FloatPredicate::ONE, cond, zero_const, "ifcond"); - - // build branch - let then_bb = self.context.append_basic_block(parent, "then"); - let else_bb = self.context.append_basic_block(parent, "else"); - let cont_bb = self.context.append_basic_block(parent, "ifcont"); - - self.builder.build_conditional_branch(cond, then_bb, else_bb); - - // build then block - self.builder.position_at_end(then_bb); - let then_val = self.compile_expr(consequence)?; - self.builder.build_unconditional_branch(cont_bb); - - let then_bb = self.builder.get_insert_block().unwrap(); - - // build else block - self.builder.position_at_end(else_bb); - let else_val = self.compile_expr(alternative)?; - self.builder.build_unconditional_branch(cont_bb); - - let else_bb = self.builder.get_insert_block().unwrap(); - - // emit merge block - self.builder.position_at_end(cont_bb); - - let phi = self.builder.build_phi(self.context.f64_type(), "iftmp"); - - phi.add_incoming(&[(&then_val, then_bb), (&else_val, else_bb)]); - - Ok(phi.as_basic_value().into_float_value()) - }, - - Expr::For { - ref var_name, - ref start, - ref end, - ref step, - ref body, - } => { - let parent = self.fn_value(); - - let start_alloca = self.create_entry_block_alloca(var_name); - let start = self.compile_expr(start)?; - - self.builder.build_store(start_alloca, start); - - // go from current block to loop block - let loop_bb = self.context.append_basic_block(parent, "loop"); - - self.builder.build_unconditional_branch(loop_bb); - self.builder.position_at_end(loop_bb); - - let old_val = self.variables.remove(var_name.as_str()); - - self.variables.insert(var_name.to_owned(), start_alloca); - - // emit body - self.compile_expr(body)?; - - // emit step - let step = match *step { - Some(ref step) => self.compile_expr(step)?, - None => self.context.f64_type().const_float(1.0), - }; - - // compile end condition - let end_cond = self.compile_expr(end)?; - - let curr_var = self.builder.build_load(start_alloca, var_name); - let next_var = self - .builder - .build_float_add(curr_var.into_float_value(), step, "nextvar"); - - self.builder.build_store(start_alloca, next_var); - - let end_cond = self.builder.build_float_compare( - FloatPredicate::ONE, - end_cond, - self.context.f64_type().const_float(0.0), - "loopcond", - ); - let after_bb = self.context.append_basic_block(parent, "afterloop"); - - self.builder.build_conditional_branch(end_cond, loop_bb, after_bb); - self.builder.position_at_end(after_bb); - - self.variables.remove(var_name); - - if let Some(val) = old_val { - self.variables.insert(var_name.to_owned(), val); - } - - Ok(self.context.f64_type().const_float(0.0)) - }, - } - } - - /// 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()) - .map(|f| f.into()) - .collect::>(); - let args_types = args_types.as_slice(); - - let fn_type = self.context.f64_type().fn_type(args_types, false); - let fn_val = self.module.add_function(proto.name.as_str(), fn_type, None); - - // set arguments names - for (i, arg) in fn_val.get_param_iter().enumerate() { - arg.into_float_value().set_name(proto.args[i].as_str()); - } - - // finally return built prototype - Ok(fn_val) - } - - /// Compiles the specified `Function` into an LLVM `FunctionValue`. - fn compile_fn(&mut self) -> Result, &'static str> { - let proto = &self.function.prototype; - let function = self.compile_prototype(proto)?; - - // got external function, returning only compiled prototype - if self.function.body.is_none() { - return Ok(function); - } - - let entry = self.context.append_basic_block(function, "entry"); - - self.builder.position_at_end(entry); - - // update fn field - self.fn_value_opt = Some(function); - - // build variables map - self.variables.reserve(proto.args.len()); - - for (i, arg) in function.get_param_iter().enumerate() { - let arg_name = proto.args[i].as_str(); - let alloca = self.create_entry_block_alloca(arg_name); - - self.builder.build_store(alloca, arg); - - self.variables.insert(proto.args[i].clone(), alloca); - } - - // compile body - let body = self.compile_expr(self.function.body.as_ref().unwrap())?; - - self.builder.build_return(Some(&body)); - - // return the whole thing after verification and optimization - if function.verify(true) { - self.fpm.run_on(&function); - - Ok(function) - } else { - unsafe { - function.delete(); - } - - Err("Invalid generated function.") - } - } - - /// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`. - pub fn compile( - context: &'ctx Context, - builder: &'a Builder<'ctx>, - pass_manager: &'a PassManager>, - module: &'a Module<'ctx>, - function: &Function, - ) -> Result, &'static str> { - let mut compiler = Compiler { - context, - builder, - fpm: pass_manager, - module, - function, - fn_value_opt: None, - variables: HashMap::new(), - }; - - compiler.compile_fn() - } -} +#[llvm_versions(4.0..=14.0)] +use crate::implementation_typed_pointers::*; // ====================================================================================== // PROGRAM ============================================================================== @@ -1243,6 +58,7 @@ pub extern "C" fn printd(x: f64) -> f64 { static EXTERNAL_FNS: [extern "C" fn(f64) -> f64; 2] = [putchard, printd]; /// Entry point of the program; acts as a REPL. +#[llvm_versions(4.0..=14.0)] pub fn main() { // use self::inkwell::support::add_symbol; let mut display_lexer_output = false; @@ -1379,3 +195,8 @@ pub fn main() { } } } + +#[llvm_versions(15.0..=latest)] +pub fn main() { + eprintln!("Kaleidoscope example does not work yet with this llvm version"); +} From 2370df0b9121643090bc49b64766b2a77e0c0a24 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 19 Dec 2022 15:53:57 +0100 Subject: [PATCH 30/34] Update all the tests (#3) --- src/builder.rs | 179 ++++++++++++++++++++++----- src/context.rs | 28 ++++- src/values/fn_value.rs | 6 + src/values/metadata_value.rs | 9 +- src/values/mod.rs | 8 +- tests/all/test_attributes.rs | 3 - tests/all/test_builder.rs | 104 ++++++++-------- tests/all/test_instruction_values.rs | 19 +-- tests/all/test_types.rs | 15 ++- tests/all/test_values.rs | 26 ++-- 10 files changed, 281 insertions(+), 116 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 4c77f9f9261..8023a1fa7b9 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -39,11 +39,14 @@ use crate::basic_block::BasicBlock; use crate::debug_info::DILocation; use crate::support::to_c_str; use crate::types::{AsTypeRef, BasicType, FloatMathType, FunctionType, IntMathType, PointerMathType, PointerType}; +#[llvm_versions(4.0..=14.0)] +use crate::values::CallableValue; use crate::values::{ AggregateValue, AggregateValueEnum, AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue, - CallableValue, FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, InstructionValue, IntMathValue, - IntValue, PhiValue, PointerMathValue, PointerValue, StructValue, VectorValue, + FloatMathValue, FunctionValue, GlobalValue, InstructionOpcode, InstructionValue, IntMathValue, IntValue, PhiValue, + PointerMathValue, PointerValue, StructValue, VectorValue, }; + #[cfg(feature = "internal-getters")] use crate::LLVMReference; use crate::{AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate}; @@ -56,6 +59,9 @@ pub struct Builder<'ctx> { _marker: PhantomData<&'ctx ()>, } +#[allow(unused)] // only used in documentation +use crate::context::Context; + impl<'ctx> Builder<'ctx> { pub(crate) unsafe fn new(builder: LLVMBuilderRef) -> Self { debug_assert!(!builder.is_null()); @@ -189,11 +195,19 @@ impl<'ctx> Builder<'ctx> { unsafe { CallSiteValue::new(value) } } - /// Builds a function call instruction. - /// [`FunctionValue`]s can be implicitly converted into a [`CallableValue`]. - /// See [`CallableValue`] for details on calling a [`PointerValue`] that points to a function. - /// - /// [`FunctionValue`]: crate::values::FunctionValue + /// Builds a function call instruction. Alias for [Builder::build_direct_call]. + #[llvm_versions(15.0..=latest)] + pub fn build_call( + &self, + function: FunctionValue<'ctx>, + args: &[BasicMetadataValueEnum<'ctx>], + name: &str, + ) -> CallSiteValue<'ctx> { + self.build_direct_call(function, args, name) + } + + /// Builds a function call instruction. The function being called is known at compile time. If + /// you want to call a function pointer, see [Builder::build_indirect_call]. /// /// # Example /// @@ -213,7 +227,7 @@ impl<'ctx> Builder<'ctx> { /// /// builder.position_at_end(entry); /// - /// let ret_val = builder.build_call(fn_type, fn_value, &[i32_arg.into(), md_string.into()], "call") + /// let ret_val = builder.build_call(fn_value, &[i32_arg.into(), md_string.into()], "call") /// .try_as_basic_value() /// .left() /// .unwrap(); @@ -221,22 +235,71 @@ impl<'ctx> Builder<'ctx> { /// builder.build_return(Some(&ret_val)); /// ``` #[llvm_versions(15.0..=latest)] - pub fn build_call( + pub fn build_direct_call( &self, - fn_ty: FunctionType<'ctx>, - function: F, + function: FunctionValue<'ctx>, args: &[BasicMetadataValueEnum<'ctx>], name: &str, - ) -> CallSiteValue<'ctx> - where - F: Into>, - { - let callable_value = function.into(); - let fn_ty_ref = fn_ty.as_type_ref(); - let fn_val_ref = callable_value.as_value_ref(); + ) -> CallSiteValue<'ctx> { + self.build_call_help(function.get_type(), function.as_value_ref(), args, name) + } + + /// Call a function pointer. Because a pointer does not carry a type, the type of the function + /// must be specified explicitly. + /// + /// See [Context::create_inline_asm] for a practical example. Basic usage looks like this: + /// + /// ```no_run + /// use inkwell::context::Context; + /// + /// // A simple function which calls itself: + /// let context = Context::create(); + /// let module = context.create_module("ret"); + /// let builder = context.create_builder(); + /// let i32_type = context.i32_type(); + /// let fn_type = i32_type.fn_type(&[i32_type.into()], false); + /// let fn_value = module.add_function("ret", fn_type, None); + /// let entry = context.append_basic_block(fn_value, "entry"); + /// let i32_arg = fn_value.get_first_param().unwrap(); + /// let md_string = context.metadata_string("a metadata"); + /// + /// builder.position_at_end(entry); + /// + /// let function_pointer = fn_value.as_global_value().as_pointer_value(); + /// let ret_val = builder.build_indirect_call(fn_value.get_type(), function_pointer, &[i32_arg.into(), md_string.into()], "call") + /// .try_as_basic_value() + /// .left() + /// .unwrap(); + /// + /// builder.build_return(Some(&ret_val)); + /// ``` + /// + #[llvm_versions(15.0..=latest)] + pub fn build_indirect_call( + &self, + function_type: FunctionType<'ctx>, + function_pointer: PointerValue<'ctx>, + args: &[BasicMetadataValueEnum<'ctx>], + name: &str, + ) -> CallSiteValue<'ctx> { + self.build_call_help(function_type, function_pointer.as_value_ref(), args, name) + } + #[llvm_versions(15.0..=latest)] + fn build_call_help( + &self, + function_type: FunctionType<'ctx>, + fn_val_ref: LLVMValueRef, + args: &[BasicMetadataValueEnum<'ctx>], + name: &str, + ) -> CallSiteValue<'ctx> { // LLVM gets upset when void return calls are named because they don't return anything - let name = if fn_ty.get_return_type().is_none() { "" } else { name }; + let name = match function_type.get_return_type() { + None => "", + Some(_) => name, + }; + + let fn_ty_ref = function_type.as_type_ref(); let c_string = to_c_str(name); let mut args: Vec = args.iter().map(|val| val.as_value_ref()).collect(); @@ -415,7 +478,7 @@ impl<'ctx> Builder<'ctx> { /// let then_block = context.append_basic_block(function2, "then_block"); /// let catch_block = context.append_basic_block(function2, "catch_block"); /// - /// let call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); + /// let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); /// /// { /// builder.position_at_end(then_block); @@ -450,21 +513,67 @@ impl<'ctx> Builder<'ctx> { /// } /// ``` #[llvm_versions(15.0..=latest)] - pub fn build_invoke( + pub fn build_invoke( + &self, + function: FunctionValue<'ctx>, + args: &[BasicValueEnum<'ctx>], + then_block: BasicBlock<'ctx>, + catch_block: BasicBlock<'ctx>, + name: &str, + ) -> CallSiteValue<'ctx> { + self.build_direct_invoke(function, args, then_block, catch_block, name) + } + + #[llvm_versions(15.0..=latest)] + pub fn build_direct_invoke( + &self, + function: FunctionValue<'ctx>, + args: &[BasicValueEnum<'ctx>], + then_block: BasicBlock<'ctx>, + catch_block: BasicBlock<'ctx>, + name: &str, + ) -> CallSiteValue<'ctx> { + self.build_invoke_help( + function.get_type(), + function.as_value_ref(), + args, + then_block, + catch_block, + name, + ) + } + + #[llvm_versions(15.0..=latest)] + pub fn build_indirect_invoke( + &self, + function_type: FunctionType<'ctx>, + function_pointer: PointerValue<'ctx>, + args: &[BasicValueEnum<'ctx>], + then_block: BasicBlock<'ctx>, + catch_block: BasicBlock<'ctx>, + name: &str, + ) -> CallSiteValue<'ctx> { + self.build_invoke_help( + function_type, + function_pointer.as_value_ref(), + args, + then_block, + catch_block, + name, + ) + } + + #[llvm_versions(15.0..=latest)] + fn build_invoke_help( &self, fn_ty: FunctionType<'ctx>, - function: F, + fn_val_ref: LLVMValueRef, args: &[BasicValueEnum<'ctx>], then_block: BasicBlock<'ctx>, catch_block: BasicBlock<'ctx>, name: &str, - ) -> CallSiteValue<'ctx> - where - F: Into>, - { - let callable_value: CallableValue<'ctx> = function.into(); + ) -> CallSiteValue<'ctx> { let fn_ty_ref = fn_ty.as_type_ref(); - let fn_val_ref = callable_value.as_value_ref(); // LLVM gets upset when void return calls are named because they don't return anything let name = if fn_ty.get_return_type().is_none() { "" } else { name }; @@ -2238,7 +2347,12 @@ impl<'ctx> Builder<'ctx> { /// builder.position_at_end(entry); /// /// let array_alloca = builder.build_alloca(array_type, "array_alloca"); + /// + /// #[cfg(not(any(feature = "llvm15-0")))] /// let array = builder.build_load(array_alloca, "array_load").into_array_value(); + /// #[cfg(any(feature = "llvm15-0"))] + /// let array = builder.build_load(i32_type, array_alloca, "array_load").into_array_value(); + /// /// let const_int1 = i32_type.const_int(2, false); /// let const_int2 = i32_type.const_int(5, false); /// let const_int3 = i32_type.const_int(6, false); @@ -2298,7 +2412,12 @@ impl<'ctx> Builder<'ctx> { /// builder.position_at_end(entry); /// /// let array_alloca = builder.build_alloca(array_type, "array_alloca"); + /// + /// #[cfg(not(any(feature = "llvm15-0")))] /// let array = builder.build_load(array_alloca, "array_load").into_array_value(); + /// #[cfg(any(feature = "llvm15-0"))] + /// let array = builder.build_load(i32_type, array_alloca, "array_load").into_array_value(); + /// /// let const_int1 = i32_type.const_int(2, false); /// let const_int2 = i32_type.const_int(5, false); /// let const_int3 = i32_type.const_int(6, false); @@ -2669,6 +2788,8 @@ impl<'ctx> Builder<'ctx> { if value.get_type().get_bit_width() < 8 || !value.get_type().get_bit_width().is_power_of_two() { return Err("The bitwidth of value must be a power of 2 and greater than 8."); } + + #[cfg(not(any(feature = "llvm15-0")))] if ptr.get_type().get_element_type() != value.get_type().into() { return Err("Pointer's pointee type must match the value's type."); } @@ -2727,6 +2848,8 @@ impl<'ctx> Builder<'ctx> { if !cmp.is_int_value() && !cmp.is_pointer_value() { return Err("The values must have pointer or integer type."); } + + #[cfg(not(any(feature = "llvm15-0")))] if ptr.get_type().get_element_type().to_basic_type_enum() != cmp.get_type() { return Err("The pointer does not point to an element of the value type."); } diff --git a/src/context.rs b/src/context.rs index e954b71ba8a..174e6960591 100644 --- a/src/context.rs +++ b/src/context.rs @@ -522,7 +522,6 @@ impl Context { /// ```no_run /// use std::convert::TryFrom; /// use inkwell::context::Context; - /// use inkwell::values::CallableValue; /// /// let context = Context::create(); /// let module = context.create_module("my_module"); @@ -555,8 +554,17 @@ impl Context { /// false, /// ); /// let params = &[context.i64_type().const_int(60, false).into(), context.i64_type().const_int(1, false).into()]; - /// let callable_value = CallableValue::try_from(asm).unwrap(); - /// builder.build_call(callable_value, params, "exit"); + /// + /// #[cfg(not(any(feature = "llvm15-0")))] + /// { + /// use inkwell::values::CallableValue; + /// let callable_value = CallableValue::try_from(asm).unwrap(); + /// builder.build_call(callable_value, params, "exit"); + /// } + /// + /// #[cfg(any(feature = "llvm15-0"))] + /// builder.build_indirect_call(asm_fn, asm, params, "exit"); + /// /// builder.build_return(None); /// ``` #[inline] @@ -1357,7 +1365,6 @@ impl<'ctx> ContextRef<'ctx> { /// ```no_run /// use std::convert::TryFrom; /// use inkwell::context::Context; - /// use inkwell::values::CallableValue; /// /// let context = Context::create(); /// let module = context.create_module("my_module"); @@ -1390,8 +1397,17 @@ impl<'ctx> ContextRef<'ctx> { /// false, /// ); /// let params = &[context.i64_type().const_int(60, false).into(), context.i64_type().const_int(1, false).into()]; - /// let callable_value = CallableValue::try_from(asm).unwrap(); - /// builder.build_call(callable_value, params, "exit"); + /// + /// #[cfg(not(any(feature = "llvm15-0")))] + /// { + /// use inkwell::values::CallableValue; + /// let callable_value = CallableValue::try_from(asm).unwrap(); + /// builder.build_call(callable_value, params, "exit"); + /// } + /// + /// #[cfg(any(feature = "llvm15-0"))] + /// builder.build_indirect_call(asm_fn, asm, params, "exit"); + /// /// builder.build_return(None); /// ``` #[inline] diff --git a/src/values/fn_value.rs b/src/values/fn_value.rs index c20b1ec9a31..ecfa03c7616 100644 --- a/src/values/fn_value.rs +++ b/src/values/fn_value.rs @@ -198,12 +198,18 @@ impl<'ctx> FunctionValue<'ctx> { LLVMDeleteFunction(self.as_value_ref()) } + #[llvm_versions(4.0..=7.0)] pub fn get_type(self) -> FunctionType<'ctx> { let ptr_type = unsafe { PointerType::new(self.fn_value.get_type()) }; ptr_type.get_element_type().into_function_type() } + #[llvm_versions(8.0..=latest)] + pub fn get_type(self) -> FunctionType<'ctx> { + unsafe { FunctionType::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) } + } + // TODOC: How this works as an exception handler pub fn has_personality_function(self) -> bool { use llvm_sys::core::LLVMHasPersonalityFn; diff --git a/src/values/metadata_value.rs b/src/values/metadata_value.rs index 3a850b7f4dc..3a796d1c6aa 100644 --- a/src/values/metadata_value.rs +++ b/src/values/metadata_value.rs @@ -32,13 +32,10 @@ pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 26; pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 28; #[cfg(any(feature = "llvm10-0", feature = "llvm11-0"))] pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 30; -#[cfg(any( - feature = "llvm12-0", - feature = "llvm13-0", - feature = "llvm14-0", - feature = "llvm15-0" -))] +#[cfg(any(feature = "llvm12-0", feature = "llvm13-0", feature = "llvm14-0",))] pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 31; +#[cfg(any(feature = "llvm15-0"))] +pub const FIRST_CUSTOM_METADATA_KIND_ID: u32 = 36; #[derive(PartialEq, Eq, Clone, Copy, Hash)] pub struct MetadataValue<'ctx> { diff --git a/src/values/mod.rs b/src/values/mod.rs index 008f64aaadf..e3a613be9dc 100644 --- a/src/values/mod.rs +++ b/src/values/mod.rs @@ -6,7 +6,6 @@ mod array_value; mod basic_value_use; #[deny(missing_docs)] mod call_site_value; -mod callable_value; mod enums; mod float_value; mod fn_value; @@ -21,11 +20,16 @@ mod struct_value; mod traits; mod vec_value; +#[cfg(not(any(feature = "llvm15-0")))] +mod callable_value; + +#[cfg(not(any(feature = "llvm15-0")))] +pub use crate::values::callable_value::CallableValue; + use crate::support::{to_c_str, LLVMString}; pub use crate::values::array_value::ArrayValue; pub use crate::values::basic_value_use::BasicValueUse; pub use crate::values::call_site_value::CallSiteValue; -pub use crate::values::callable_value::CallableValue; pub use crate::values::enums::{AggregateValueEnum, AnyValueEnum, BasicMetadataValueEnum, BasicValueEnum}; pub use crate::values::float_value::FloatValue; pub use crate::values::fn_value::FunctionValue; diff --git a/tests/all/test_attributes.rs b/tests/all/test_attributes.rs index e6101c37ebb..240333b8124 100644 --- a/tests/all/test_attributes.rs +++ b/tests/all/test_attributes.rs @@ -151,10 +151,7 @@ fn test_attributes_on_call_site_values() { builder.position_at_end(entry_bb); - #[cfg(not(feature = "llvm15-0"))] let call_site_value = builder.build_call(fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); - #[cfg(feature = "llvm15-0")] - let call_site_value = builder.build_call(fn_type, fn_value, &[i32_type.const_int(1, false).into()], "my_fn"); builder.build_return(None); diff --git a/tests/all/test_builder.rs b/tests/all/test_builder.rs index 8a4a3388345..4ca7dfaa909 100644 --- a/tests/all/test_builder.rs +++ b/tests/all/test_builder.rs @@ -1,5 +1,4 @@ use inkwell::context::Context; -use inkwell::values::CallableValue; use inkwell::{AddressSpace, AtomicOrdering, AtomicRMWBinOp, OptimizationLevel}; use std::convert::TryFrom; @@ -28,10 +27,7 @@ fn test_build_call() { builder.position_at_end(basic_block2); - #[cfg(not(feature = "llvm15-0"))] let pi2_call_site = builder.build_call(function, &[], "get_pi"); - #[cfg(feature = "llvm15-0")] - let pi2_call_site = builder.build_call(fn_type, function, &[], "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -64,11 +60,14 @@ fn test_build_call() { #[cfg(feature = "llvm15-0")] let load = builder.build_load(fn_ptr_type, alloca, "load").into_pointer_value(); - let callable_value = CallableValue::try_from(load).unwrap(); #[cfg(not(feature = "llvm15-0"))] - builder.build_call(callable_value, &[], "call"); + { + use inkwell::values::CallableValue; + let callable_value = CallableValue::try_from(load).unwrap(); + builder.build_call(callable_value, &[], "call"); + } #[cfg(feature = "llvm15-0")] - builder.build_call(fn_type2, callable_value, &[], "call"); + builder.build_indirect_call(fn_type2, load, &[], "call"); builder.build_return(None); assert!(module.verify().is_ok()); @@ -101,10 +100,7 @@ fn test_build_invoke_cleanup_resume() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); - #[cfg(not(feature = "llvm15-0"))] let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); - #[cfg(feature = "llvm15-0")] - let call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!call_site.is_tail_call()); @@ -171,10 +167,7 @@ fn test_build_invoke_catch_all() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); - #[cfg(not(feature = "llvm15-0"))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); - #[cfg(feature = "llvm15-0")] - let pi2_call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -245,10 +238,7 @@ fn landing_pad_filter() { let then_block = context.append_basic_block(function2, "then_block"); let catch_block = context.append_basic_block(function2, "catch_block"); - #[cfg(not(feature = "llvm15-0"))] let pi2_call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi"); - #[cfg(feature = "llvm15-0")] - let pi2_call_site = builder.build_invoke(fn_type, function, &[], then_block, catch_block, "get_pi"); assert!(!pi2_call_site.is_tail_call()); @@ -1031,7 +1021,8 @@ fn run_memcpy_on<'ctx>( builder.position_at_end(entry); let len_value = i64_type.const_int(array_len as u64, false); - let array_type = i32_type.array_type(array_len as u32); + let element_type = i32_type; + let array_type = element_type.array_type(array_len as u32); let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap(); // Initialize the array with the values [1, 2, 3, 4] @@ -1040,7 +1031,7 @@ fn run_memcpy_on<'ctx>( #[cfg(not(feature = "llvm15-0"))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(feature = "llvm15-0")] - let elem_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; + let elem_ptr = unsafe { builder.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); builder.build_store(elem_ptr, int_val); @@ -1054,7 +1045,7 @@ fn run_memcpy_on<'ctx>( #[cfg(not(feature = "llvm15-0"))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(feature = "llvm15-0")] - let dest_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; + let dest_ptr = unsafe { builder.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index") }; builder.build_memcpy(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1085,7 +1076,7 @@ fn test_memcpy() { let func = execution_engine .get_function:: *const i32>("test_fn") .unwrap(); - let actual = std::slice::from_raw_parts(func.call(), 4); + let actual: &[i32] = std::slice::from_raw_parts(func.call(), 4); assert_eq!(&[1, 2, 1, 2], actual); } @@ -1108,7 +1099,8 @@ fn run_memmove_on<'ctx>( builder.position_at_end(entry); let len_value = i64_type.const_int(array_len as u64, false); - let array_type = i32_type.array_type(array_len as u32); + let element_type = i32_type; + let array_type = element_type.array_type(array_len as u32); let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap(); // Initialize the array with the values [1, 2, 3, 4] @@ -1117,7 +1109,7 @@ fn run_memmove_on<'ctx>( #[cfg(not(feature = "llvm15-0"))] let elem_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(feature = "llvm15-0")] - let elem_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; + let elem_ptr = unsafe { builder.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index") }; let int_val = i32_type.const_int(index + 1, false); builder.build_store(elem_ptr, int_val); @@ -1131,7 +1123,7 @@ fn run_memmove_on<'ctx>( #[cfg(not(feature = "llvm15-0"))] let dest_ptr = unsafe { builder.build_in_bounds_gep(array_ptr, &[index_val], "index") }; #[cfg(feature = "llvm15-0")] - let dest_ptr = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index_val], "index") }; + let dest_ptr = unsafe { builder.build_in_bounds_gep(element_type, array_ptr, &[index_val], "index") }; builder.build_memmove(dest_ptr, alignment, array_ptr, alignment, size_val)?; @@ -1186,7 +1178,8 @@ fn run_memset_on<'ctx>( builder.position_at_end(entry); let len_value = i64_type.const_int(array_len as u64, false); - let array_type = i32_type.array_type(array_len as u32); + let element_type = i32_type; + let array_type = element_type.array_type(array_len as u32); let array_ptr = builder.build_array_malloc(i32_type, len_value, "array_ptr").unwrap(); let elems_to_copy = 2; @@ -1201,7 +1194,7 @@ fn run_memset_on<'ctx>( #[cfg(not(feature = "llvm15-0"))] let part_2 = unsafe { builder.build_in_bounds_gep(array_ptr, &[index], "index") }; #[cfg(feature = "llvm15-0")] - let part_2 = unsafe { builder.build_in_bounds_gep(array_type, array_ptr, &[index], "index") }; + let part_2 = unsafe { builder.build_in_bounds_gep(element_type, array_ptr, &[index], "index") }; builder.build_memset(part_2, alignment, val, size_val)?; builder.build_return(Some(&array_ptr)); @@ -1309,10 +1302,13 @@ fn test_atomicrmw() { let result = builder.build_atomicrmw(AtomicRMWBinOp::Add, ptr_value, zero_value, AtomicOrdering::Unordered); assert!(result.is_ok()); - let ptr_value = i64_type.ptr_type(AddressSpace::Zero).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_err()); + #[cfg(not(any(feature = "llvm15-0")))] + { + let ptr_value = i64_type.ptr_type(AddressSpace::Zero).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_err()); + } let ptr_value = i31_type.ptr_type(AddressSpace::Zero).get_undef(); let zero_value = i31_type.const_zero(); @@ -1414,17 +1410,20 @@ fn test_cmpxchg() { ); assert!(result.is_err()); - let ptr_value = i32_ptr_ptr_type.get_undef(); - let zero_value = i32_type.const_zero(); - let neg_one_value = i32_type.const_all_ones(); - let result = builder.build_cmpxchg( - ptr_value, - zero_value, - neg_one_value, - AtomicOrdering::Monotonic, - AtomicOrdering::Monotonic, - ); - assert!(result.is_err()); + #[cfg(not(any(feature = "llvm15-0")))] + { + let ptr_value = i32_ptr_ptr_type.get_undef(); + let zero_value = i32_type.const_zero(); + let neg_one_value = i32_type.const_all_ones(); + let result = builder.build_cmpxchg( + ptr_value, + zero_value, + neg_one_value, + AtomicOrdering::Monotonic, + AtomicOrdering::Monotonic, + ); + assert!(result.is_err()); + } let ptr_value = i32_ptr_type.get_undef(); let zero_value = i64_type.const_zero(); @@ -1462,17 +1461,20 @@ fn test_cmpxchg() { ); assert!(result.is_ok()); - let ptr_value = i32_ptr_type.get_undef(); - let zero_value = i32_ptr_type.const_zero(); - let neg_one_value = i32_ptr_type.const_zero(); - let result = builder.build_cmpxchg( - ptr_value, - zero_value, - neg_one_value, - AtomicOrdering::Monotonic, - AtomicOrdering::Monotonic, - ); - assert!(result.is_err()); + #[cfg(not(any(feature = "llvm15-0")))] + { + let ptr_value = i32_ptr_type.get_undef(); + let zero_value = i32_ptr_type.const_zero(); + let neg_one_value = i32_ptr_type.const_zero(); + let result = builder.build_cmpxchg( + ptr_value, + zero_value, + neg_one_value, + AtomicOrdering::Monotonic, + AtomicOrdering::Monotonic, + ); + assert!(result.is_err()); + } } #[test] diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index a1410941639..000efbdd5ac 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -4,6 +4,7 @@ use inkwell::values::{BasicValue, InstructionOpcode::*}; use inkwell::{AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate}; #[test] +#[ignore] fn test_operands() { let context = Context::create(); let module = context.create_module("ivs"); @@ -45,23 +46,25 @@ fn test_operands() { let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap(); let free_operand1 = free_instruction.get_operand(1).unwrap().left().unwrap(); - let free_operand0_instruction = free_operand0.as_instruction_value().unwrap(); assert!(free_operand0.is_pointer_value()); // (implictly casted) i8* arg1 assert!(free_operand1.is_pointer_value()); // Free function ptr - assert_eq!(free_operand0_instruction.get_opcode(), BitCast); - assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1); - assert!(free_operand0_instruction.get_operand(1).is_none()); - assert!(free_operand0_instruction.get_operand(2).is_none()); assert!(free_instruction.get_operand(2).is_none()); assert!(free_instruction.get_operand(3).is_none()); assert!(free_instruction.get_operand(4).is_none()); + // let free_operand0_instruction = free_operand0.as_instruction_value().unwrap(); + // assert_eq!(free_operand0_instruction.get_opcode(), BitCast); + // assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1); + // assert!(free_operand0_instruction.get_operand(1).is_none()); + // assert!(free_operand0_instruction.get_operand(2).is_none()); + assert!(module.verify().is_ok()); assert!(free_instruction.set_operand(0, arg1)); // Module is no longer valid because free takes an i8* not f32* + #[cfg(not(feature = "llvm15-0"))] assert!(module.verify().is_err()); assert!(free_instruction.set_operand(0, free_operand0)); @@ -79,6 +82,7 @@ fn test_operands() { assert!(return_instruction.get_operand(2).is_none()); // Test Uses + /* let bitcast_use_value = free_operand0_instruction .get_first_use() .unwrap() @@ -88,6 +92,7 @@ fn test_operands() { let free_call_param = free_instruction.get_operand(0).unwrap().left().unwrap(); assert_eq!(bitcast_use_value, free_call_param); + */ // These instructions/calls don't return any ir value so they aren't used anywhere assert!(store_instruction.get_first_use().is_none()); @@ -420,7 +425,7 @@ fn test_mem_instructions() { #[cfg(not(feature = "llvm15-0"))] let load = builder.build_load(arg1, ""); #[cfg(feature = "llvm15-0")] - let load = builder.build_load(f32_ptr_type, arg1, ""); + let load = builder.build_load(f32_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); assert_eq!(store_instruction.get_volatile().unwrap(), false); @@ -486,7 +491,7 @@ fn test_atomic_ordering_mem_instructions() { #[cfg(not(feature = "llvm15-0"))] let load = builder.build_load(arg1, ""); #[cfg(feature = "llvm15-0")] - let load = builder.build_load(f32_ptr_type, arg1, ""); + let load = builder.build_load(f32_type, arg1, ""); let load_instruction = load.as_instruction_value().unwrap(); assert_eq!( diff --git a/tests/all/test_types.rs b/tests/all/test_types.rs index e0d25e3c0ce..191062ed628 100644 --- a/tests/all/test_types.rs +++ b/tests/all/test_types.rs @@ -312,7 +312,16 @@ fn test_const_zero() { struct_zero.print_to_string().to_str(), Ok("{ i8, fp128 } zeroinitializer") ); - assert_eq!(ptr_zero.print_to_string().to_str(), Ok("double* null")); + + // handle opaque pointers + let ptr_type = if cfg!(any(feature = "llvm15-0")) { + "ptr null" + } else { + "double* null" + }; + + assert_eq!(ptr_zero.print_to_string().to_str(), Ok(ptr_type)); + assert_eq!(vec_zero.print_to_string().to_str(), Ok("<42 x double> zeroinitializer")); assert_eq!( array_zero.print_to_string().to_str(), @@ -345,6 +354,8 @@ fn test_ptr_type() { let ptr_type = i8_type.ptr_type(AddressSpace::Zero); assert_eq!(ptr_type.get_address_space(), AddressSpace::Zero); + + #[cfg(not(feature = "llvm15-0"))] assert_eq!(ptr_type.get_element_type().into_int_type(), i8_type); // Fn ptr: @@ -352,7 +363,9 @@ fn test_ptr_type() { let fn_type = void_type.fn_type(&[], false); let fn_ptr_type = fn_type.ptr_type(AddressSpace::Zero); + #[cfg(not(feature = "llvm15-0"))] assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type); + assert_eq!(fn_ptr_type.get_context(), context); } diff --git a/tests/all/test_values.rs b/tests/all/test_values.rs index d8f071817f2..417f14affd4 100644 --- a/tests/all/test_values.rs +++ b/tests/all/test_values.rs @@ -4,7 +4,7 @@ use inkwell::comdat::ComdatSelectionKind; use inkwell::context::Context; use inkwell::module::Linkage::*; use inkwell::types::{StringRadix, VectorType}; -use inkwell::values::{AnyValue, CallableValue, InstructionOpcode::*, FIRST_CUSTOM_METADATA_KIND_ID}; +use inkwell::values::{AnyValue, InstructionOpcode::*, FIRST_CUSTOM_METADATA_KIND_ID}; use inkwell::{AddressSpace, DLLStorageClass, GlobalVisibility, ThreadLocalMode}; use std::convert::TryFrom; @@ -38,11 +38,7 @@ fn test_call_site() { let fn_type = void_type.fn_type(&[], false); let function = module.add_function("do_nothing", fn_type, None); - - #[cfg(not(feature = "llvm15-0"))] let call_site = builder.build_call(function, &[], "to_infinity_and_beyond"); - #[cfg(feature = "llvm15-0")] - let call_site = builder.build_call(fn_type, function, &[], "to_infinity_and_beyond"); assert_eq!(call_site.count_arguments(), 0); assert!(!call_site.is_tail_call()); @@ -925,6 +921,9 @@ fn test_allocations() { builder.position_at_end(entry_block); + // handle opaque pointers + let ptr_type = if cfg!(any(feature = "llvm15-0")) { "ptr" } else { "i32*" }; + // REVIEW: Alloca (and possibly malloc) seem to be prone to segfaulting // when called with a builder that isn't positioned. I wonder if other // builder methods have this problem? We could make builder subtypes: @@ -934,21 +933,21 @@ fn test_allocations() { let stack_ptr = builder.build_alloca(i32_type, "stack_ptr"); - assert_eq!(stack_ptr.get_type().print_to_string().to_str(), Ok("i32*")); + assert_eq!(stack_ptr.get_type().print_to_string().to_str(), Ok(ptr_type)); let stack_array = builder.build_array_alloca(i32_type, i32_three, "stack_array"); - assert_eq!(stack_array.get_type().print_to_string().to_str(), Ok("i32*")); + assert_eq!(stack_array.get_type().print_to_string().to_str(), Ok(ptr_type)); let heap_ptr = builder.build_malloc(i32_type, "heap_ptr"); assert!(heap_ptr.is_ok()); - assert_eq!(heap_ptr.unwrap().get_type().print_to_string().to_str(), Ok("i32*")); + assert_eq!(heap_ptr.unwrap().get_type().print_to_string().to_str(), Ok(ptr_type)); let heap_array = builder.build_array_malloc(i32_type, i32_three, "heap_array"); assert!(heap_array.is_ok()); - assert_eq!(heap_array.unwrap().get_type().print_to_string().to_str(), Ok("i32*")); + assert_eq!(heap_array.unwrap().get_type().print_to_string().to_str(), Ok(ptr_type)); let bad_malloc_res = builder.build_malloc(unsized_type, ""); @@ -1149,11 +1148,14 @@ fn test_non_fn_ptr_called() { let i8_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value(); builder.position_at_end(bb); - let callable_value = CallableValue::try_from(i8_ptr_param).unwrap(); #[cfg(not(feature = "llvm15-0"))] - builder.build_call(callable_value, &[], "call"); + { + use inkwell::values::CallableValue; + let callable_value = CallableValue::try_from(i8_ptr_param).unwrap(); + builder.build_call(callable_value, &[], "call"); + } #[cfg(feature = "llvm15-0")] - builder.build_call(i8_ptr_type.fn_type(&[], false), callable_value, &[], "call"); + builder.build_indirect_call(i8_ptr_type.fn_type(&[], false), i8_ptr_param, &[], "call"); builder.build_return(None); assert!(module.verify().is_ok()); From 71978624d0087d31919901cf2a55fc58e810eae7 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Wed, 21 Dec 2022 15:57:38 +0200 Subject: [PATCH 31/34] Fix some compile errors and warnings --- src/builder.rs | 10 +++++----- src/types/ptr_type.rs | 1 - src/values/fn_value.rs | 4 +++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index d2f5b00e065..9c5fea0e90f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -501,7 +501,7 @@ impl<'ctx> Builder<'ctx> { /// }; /// /// // type of an exception in C++ - /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Zero); + /// let i8_ptr_type = context.i32_type().ptr_type(AddressSpace::default()); /// let i32_type = context.i32_type(); /// let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false); /// @@ -1021,10 +1021,10 @@ impl<'ctx> Builder<'ctx> { /// let module = context.create_module("struct_gep"); /// let void_type = context.void_type(); /// let i32_ty = context.i32_type(); - /// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Zero); + /// let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::default()); /// let field_types = &[i32_ty.into(), i32_ty.into()]; /// let struct_ty = context.struct_type(field_types, false); - /// let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::Zero); + /// let struct_ptr_ty = struct_ty.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); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -1134,7 +1134,7 @@ impl<'ctx> Builder<'ctx> { /// let builder = context.create_builder(); /// let void_type = context.void_type(); /// let i32_type = context.i32_type(); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); + /// let i32_ptr_type = i32_type.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); /// let entry = context.append_basic_block(fn_value, "entry"); @@ -1258,7 +1258,7 @@ impl<'ctx> Builder<'ctx> { /// let module = context.create_module("ret"); /// let builder = context.create_builder(); /// let i32_type = context.i32_type(); - /// let i32_ptr_type = i32_type.ptr_type(AddressSpace::Zero); + /// let i32_ptr_type = i32_type.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); /// let entry = context.append_basic_block(fn_value, "entry"); diff --git a/src/types/ptr_type.rs b/src/types/ptr_type.rs index fedf719e098..bb8e8c1e4c1 100644 --- a/src/types/ptr_type.rs +++ b/src/types/ptr_type.rs @@ -9,7 +9,6 @@ use crate::values::{ArrayValue, AsValueRef, IntValue, PointerValue}; use crate::AddressSpace; use crate::types::enums::BasicMetadataTypeEnum; -use std::convert::TryFrom; use std::fmt::{self, Display}; /// A `PointerType` is the type of a pointer constant or variable. diff --git a/src/values/fn_value.rs b/src/values/fn_value.rs index ecfa03c7616..ad1261927e7 100644 --- a/src/values/fn_value.rs +++ b/src/values/fn_value.rs @@ -25,7 +25,7 @@ use crate::basic_block::BasicBlock; use crate::debug_info::DISubprogram; use crate::module::Linkage; use crate::support::to_c_str; -use crate::types::{FunctionType, PointerType}; +use crate::types::FunctionType; use crate::values::traits::{AnyValue, AsValueRef}; use crate::values::{BasicValueEnum, GlobalValue, Value}; @@ -200,6 +200,8 @@ impl<'ctx> FunctionValue<'ctx> { #[llvm_versions(4.0..=7.0)] 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() From 8a01251807e67704e3602e35a3dbba8006c1ae3a Mon Sep 17 00:00:00 2001 From: Alex Z Date: Sun, 15 Jan 2023 14:17:56 +0200 Subject: [PATCH 32/34] Some types and tests fixes --- src/builder.rs | 4 +++- src/types/ptr_type.rs | 5 ++++- tests/all/test_instruction_values.rs | 12 +++++------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 9c5fea0e90f..ecf0e2a1b5f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -34,6 +34,8 @@ use llvm_sys::core::{LLVMBuildIntCast2, LLVMBuildMemCpy, LLVMBuildMemMove, LLVMB use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef}; +#[llvm_versions(7.0..=8.0)] +use crate::context::AsContextRef; use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; @@ -2882,7 +2884,7 @@ impl<'ctx> Builder<'ctx> { /// Set the debug info source location of the instruction currently pointed at by the builder #[llvm_versions(7.0..=8.0)] - pub fn set_current_debug_location(&self, context: &'ctx crate::context::Context, location: DILocation<'ctx>) { + pub fn set_current_debug_location(&self, context: impl AsContextRef<'ctx>, location: DILocation<'ctx>) { use llvm_sys::core::LLVMMetadataAsValue; use llvm_sys::core::LLVMSetCurrentDebugLocation; unsafe { diff --git a/src/types/ptr_type.rs b/src/types/ptr_type.rs index bb8e8c1e4c1..7ebe95f7581 100644 --- a/src/types/ptr_type.rs +++ b/src/types/ptr_type.rs @@ -4,7 +4,9 @@ use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef}; use crate::context::ContextRef; use crate::support::LLVMString; use crate::types::traits::AsTypeRef; -use crate::types::{AnyTypeEnum, ArrayType, FunctionType, Type, VectorType}; +#[llvm_versions(4.0..=14.0)] +use crate::types::AnyTypeEnum; +use crate::types::{ArrayType, FunctionType, Type, VectorType}; use crate::values::{ArrayValue, AsValueRef, IntValue, PointerValue}; use crate::AddressSpace; @@ -257,6 +259,7 @@ impl<'ctx> PointerType<'ctx> { /// /// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type); /// ``` + #[llvm_versions(4.0..=14.0)] pub fn get_element_type(self) -> AnyTypeEnum<'ctx> { self.ptr_type.get_element_type() } diff --git a/tests/all/test_instruction_values.rs b/tests/all/test_instruction_values.rs index 5252912b078..539b685a866 100644 --- a/tests/all/test_instruction_values.rs +++ b/tests/all/test_instruction_values.rs @@ -53,11 +53,11 @@ fn test_operands() { assert!(free_instruction.get_operand(3).is_none()); assert!(free_instruction.get_operand(4).is_none()); - // let free_operand0_instruction = free_operand0.as_instruction_value().unwrap(); - // assert_eq!(free_operand0_instruction.get_opcode(), BitCast); - // assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1); - // assert!(free_operand0_instruction.get_operand(1).is_none()); - // assert!(free_operand0_instruction.get_operand(2).is_none()); + let free_operand0_instruction = free_operand0.as_instruction_value().unwrap(); + assert_eq!(free_operand0_instruction.get_opcode(), BitCast); + assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1); + assert!(free_operand0_instruction.get_operand(1).is_none()); + assert!(free_operand0_instruction.get_operand(2).is_none()); assert!(module.verify().is_ok()); @@ -82,7 +82,6 @@ fn test_operands() { assert!(return_instruction.get_operand(2).is_none()); // Test Uses - /* let bitcast_use_value = free_operand0_instruction .get_first_use() .unwrap() @@ -92,7 +91,6 @@ fn test_operands() { let free_call_param = free_instruction.get_operand(0).unwrap().left().unwrap(); assert_eq!(bitcast_use_value, free_call_param); - */ // These instructions/calls don't return any ir value so they aren't used anywhere assert!(store_instruction.get_first_use().is_none()); From 5f978cb98a99b6fc0ab725c015ccf6a8b9b34513 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Mon, 16 Jan 2023 12:03:24 +0200 Subject: [PATCH 33/34] Fix the LLVM 8 compile error --- src/builder.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index ecf0e2a1b5f..0e639659aec 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -34,9 +34,9 @@ use llvm_sys::core::{LLVMBuildIntCast2, LLVMBuildMemCpy, LLVMBuildMemMove, LLVMB use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef}; +use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=8.0)] use crate::context::AsContextRef; -use crate::basic_block::BasicBlock; #[llvm_versions(7.0..=latest)] use crate::debug_info::DILocation; use crate::support::to_c_str; @@ -2888,10 +2888,7 @@ impl<'ctx> Builder<'ctx> { use llvm_sys::core::LLVMMetadataAsValue; use llvm_sys::core::LLVMSetCurrentDebugLocation; unsafe { - LLVMSetCurrentDebugLocation( - self.builder, - LLVMMetadataAsValue(context.context.0, location.metadata_ref), - ); + LLVMSetCurrentDebugLocation(self.builder, LLVMMetadataAsValue(context.as_ctx_ref(), location.metadata_ref)); } } From 0ab93773deeac31284377523dd146ae62121a054 Mon Sep 17 00:00:00 2001 From: Alex Z Date: Tue, 17 Jan 2023 18:42:23 +0200 Subject: [PATCH 34/34] Try conditional compilation on doc tests --- src/builder.rs | 5 ++++- src/types/array_type.rs | 1 + src/types/float_type.rs | 1 + src/types/fn_type.rs | 1 + src/types/int_type.rs | 1 + src/types/ptr_type.rs | 1 + src/types/struct_type.rs | 1 + src/types/vec_type.rs | 1 + 8 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index 0e639659aec..319999515ae 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2888,7 +2888,10 @@ impl<'ctx> Builder<'ctx> { use llvm_sys::core::LLVMMetadataAsValue; use llvm_sys::core::LLVMSetCurrentDebugLocation; unsafe { - LLVMSetCurrentDebugLocation(self.builder, LLVMMetadataAsValue(context.as_ctx_ref(), location.metadata_ref)); + LLVMSetCurrentDebugLocation( + self.builder, + LLVMMetadataAsValue(context.as_ctx_ref(), location.metadata_ref), + ); } } diff --git a/src/types/array_type.rs b/src/types/array_type.rs index 34b4e9247ad..4309b9aad32 100644 --- a/src/types/array_type.rs +++ b/src/types/array_type.rs @@ -76,6 +76,7 @@ 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(not(feature = "llvm15-0"))] /// assert_eq!(i8_array_ptr_type.get_element_type().into_array_type(), i8_array_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/float_type.rs b/src/types/float_type.rs index 9e3f405fdf2..e7b92006506 100644 --- a/src/types/float_type.rs +++ b/src/types/float_type.rs @@ -215,6 +215,7 @@ impl<'ctx> FloatType<'ctx> { /// let f32_type = context.f32_type(); /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default()); /// + /// #[cfg(not(feature = "llvm15-0"))] /// assert_eq!(f32_ptr_type.get_element_type().into_float_type(), f32_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/fn_type.rs b/src/types/fn_type.rs index 69ecdd0b269..c831b7bc792 100644 --- a/src/types/fn_type.rs +++ b/src/types/fn_type.rs @@ -45,6 +45,7 @@ impl<'ctx> FunctionType<'ctx> { /// let fn_type = f32_type.fn_type(&[], false); /// let fn_ptr_type = fn_type.ptr_type(AddressSpace::default()); /// + /// #[cfg(not(feature = "llvm15-0"))] /// assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/int_type.rs b/src/types/int_type.rs index e1d24b59f5b..9580e4f051c 100644 --- a/src/types/int_type.rs +++ b/src/types/int_type.rs @@ -310,6 +310,7 @@ impl<'ctx> IntType<'ctx> { /// let i8_type = context.i8_type(); /// let i8_ptr_type = i8_type.ptr_type(AddressSpace::default()); /// + /// #[cfg(not(feature = "llvm15-0"))] /// assert_eq!(i8_ptr_type.get_element_type().into_int_type(), i8_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/ptr_type.rs b/src/types/ptr_type.rs index 7ebe95f7581..a52de1dc416 100644 --- a/src/types/ptr_type.rs +++ b/src/types/ptr_type.rs @@ -79,6 +79,7 @@ impl<'ctx> PointerType<'ctx> { /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default()); /// let f32_ptr_ptr_type = f32_ptr_type.ptr_type(AddressSpace::default()); /// + /// #[cfg(not(feature = "llvm15-0"))] /// assert_eq!(f32_ptr_ptr_type.get_element_type().into_pointer_type(), f32_ptr_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/struct_type.rs b/src/types/struct_type.rs index 3603376a051..bf12a44060b 100644 --- a/src/types/struct_type.rs +++ b/src/types/struct_type.rs @@ -192,6 +192,7 @@ 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(not(feature = "llvm15-0"))] /// assert_eq!(struct_ptr_type.get_element_type().into_struct_type(), struct_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> { diff --git a/src/types/vec_type.rs b/src/types/vec_type.rs index 5e042d5b551..641833b0a45 100644 --- a/src/types/vec_type.rs +++ b/src/types/vec_type.rs @@ -181,6 +181,7 @@ 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(not(feature = "llvm15-0"))] /// assert_eq!(f32_vec_ptr_type.get_element_type().into_vector_type(), f32_vec_type); /// ``` pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> {