about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src/llvm
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-06-14 16:43:34 +0000
committerbors <bors@rust-lang.org>2025-06-14 16:43:34 +0000
commitcc87afd8c0f9992d29581a0c26075be0962be8c4 (patch)
treeebed57c7bf3bba09df401b89c9323f4b3584912e /compiler/rustc_codegen_llvm/src/llvm
parent4a73e3c224465c0c0e71b39b479a0911460dd794 (diff)
parentd56fcd968d1334bf0c80205fb805a88999fffb5a (diff)
downloadrust-cc87afd8c0f9992d29581a0c26075be0962be8c4.tar.gz
rust-cc87afd8c0f9992d29581a0c26075be0962be8c4.zip
Auto merge of #142259 - sayantn:simplify-intrinsics, r=workingjubilee
Simplify implementation of Rust intrinsics by using type parameters in the cache

The current implementation of intrinsics have a lot of duplication to handle different overloads of overloaded LLVM intrinsic. This PR uses the **base name and the type parameters** in the cache instead of the full, overloaded name. This has the benefit that `call_intrinsic` doesn't need to provide the full name, rather the type parameters (which is most of the time more available). This uses `LLVMIntrinsicCopyOverloadedName2` to get the overloaded name from the base name and the type parameters, and only uses it to declare the function.

(originally was part of rust-lang/rust#140763, split off later)

`@rustbot` label A-codegen A-LLVM
r? codegen
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/llvm')
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs45
2 files changed, 56 insertions, 1 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index e27fbf94f34..59c61db5fcd 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -15,6 +15,7 @@
 
 use std::fmt::Debug;
 use std::marker::PhantomData;
+use std::num::NonZero;
 use std::ptr;
 
 use bitflags::bitflags;
@@ -1195,6 +1196,17 @@ unsafe extern "C" {
     // Operations on functions
     pub(crate) fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint);
 
+    // Operations about llvm intrinsics
+    pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;
+    pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero<c_uint>) -> Bool;
+    pub(crate) fn LLVMIntrinsicCopyOverloadedName2<'a>(
+        Mod: &'a Module,
+        ID: NonZero<c_uint>,
+        ParamTypes: *const &'a Type,
+        ParamCount: size_t,
+        NameLength: *mut size_t,
+    ) -> *mut c_char;
+
     // Operations on parameters
     pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;
     pub(crate) safe fn LLVMCountParams(Fn: &Value) -> c_uint;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index ed23f911930..bc3538c768d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -1,9 +1,10 @@
 #![allow(non_snake_case)]
 
 use std::ffi::{CStr, CString};
-use std::ptr;
+use std::num::NonZero;
 use std::str::FromStr;
 use std::string::FromUtf8Error;
+use std::{ptr, slice};
 
 use libc::c_uint;
 use rustc_abi::{Align, Size, WrappingRange};
@@ -327,6 +328,48 @@ pub(crate) fn get_value_name(value: &Value) -> &[u8] {
     }
 }
 
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct Intrinsic {
+    id: NonZero<c_uint>,
+}
+
+impl Intrinsic {
+    pub(crate) fn lookup(name: &[u8]) -> Option<Self> {
+        let id = unsafe { LLVMLookupIntrinsicID(name.as_c_char_ptr(), name.len()) };
+        NonZero::new(id).map(|id| Self { id })
+    }
+
+    pub(crate) fn is_overloaded(self) -> bool {
+        unsafe { LLVMIntrinsicIsOverloaded(self.id) == True }
+    }
+
+    pub(crate) fn overloaded_name<'ll>(
+        self,
+        llmod: &'ll Module,
+        type_params: &[&'ll Type],
+    ) -> String {
+        let mut len = 0;
+        let ptr = unsafe {
+            LLVMIntrinsicCopyOverloadedName2(
+                llmod,
+                self.id,
+                type_params.as_ptr(),
+                type_params.len(),
+                &mut len,
+            )
+        };
+
+        let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), len) };
+        let copied = str::from_utf8(slice).expect("Non-UTF8 intrinsic name").to_string();
+
+        unsafe {
+            libc::free(ptr.cast());
+        }
+
+        copied
+    }
+}
+
 /// Safe wrapper for `LLVMSetValueName2` from a byte slice
 pub(crate) fn set_value_name(value: &Value, name: &[u8]) {
     unsafe {