Rollup merge of #113716 - DianQK:add-no_builtins-to-function, r=pnkfelix
Add the `no-builtins` attribute to functions when `no_builtins` is applied at the crate level. **When `no_builtins` is applied at the crate level, we should add the `no-builtins` attribute to each function to ensure it takes effect in LTO.** This is also the reason why no_builtins does not take effect in LTO as mentioned in #35540. Now, `#![no_builtins]` should be similar to `-fno-builtin` in clang/gcc, see https://clang.godbolt.org/z/z4j6Wsod5. Next, we should make `#![no_builtins]` participate in LTO again. That makes sense, as LTO also takes into consideration function-level instruction optimizations, such as the MachineOutliner. More importantly, when a user writes a large `#![no_builtins]` crate, they would like this crate to participate in LTO as well. We should also add a function-level no_builtins attribute to allow users to have more control over it. This is similar to Clang's `__attribute__((no_builtin))` feature, see https://clang.godbolt.org/z/Wod6KK6eq. Before implementing this feature, maybe we should discuss whether to support more fine-grained control, such as `__attribute__((no_builtin("memcpy")))`. Related discussions: - #109821 - #35540 Next (a separate pull request?): - [ ] Revert #35637 - [ ] Add a function-level `no_builtin` attribute?
This commit is contained in:
commit
c1d6d322f4
@ -335,6 +335,10 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
||||
to_add.extend(probestack_attr(cx));
|
||||
to_add.extend(stackprotector_attr(cx));
|
||||
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
|
||||
to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
|
||||
}
|
||||
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
|
||||
to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
|
||||
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
@ -60,6 +60,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
}
|
||||
|
||||
// When `no_builtins` is applied at the crate level, we should add the
|
||||
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
if no_builtins {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
||||
}
|
||||
|
||||
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
|
||||
|
||||
let mut inline_span = None;
|
||||
|
@ -100,6 +100,8 @@ bitflags! {
|
||||
const REALLOCATOR = 1 << 18;
|
||||
/// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
|
||||
const ALLOCATOR_ZEROED = 1 << 19;
|
||||
/// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
|
||||
const NO_BUILTINS = 1 << 20;
|
||||
}
|
||||
}
|
||||
|
||||
|
24
tests/codegen/no_builtins-at-crate.rs
Normal file
24
tests/codegen/no_builtins-at-crate.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// compile-flags: -C opt-level=1
|
||||
|
||||
#![no_builtins]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// CHECK: define
|
||||
// CHECK-SAME: @__aeabi_memcpy
|
||||
// CHECK-SAME: #0
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) {
|
||||
// CHECK: call
|
||||
// CHECK-SAME: @memcpy(
|
||||
memcpy(dest, src, size);
|
||||
}
|
||||
|
||||
// CHECK: declare
|
||||
// CHECK-SAME: @memcpy
|
||||
// CHECK-SAME: #0
|
||||
extern "C" {
|
||||
pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||
}
|
||||
|
||||
// CHECK: attributes #0
|
||||
// CHECK-SAME: "no-builtins"
|
9
tests/run-make/no-builtins-attribute/Makefile
Normal file
9
tests/run-make/no-builtins-attribute/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
include ../tools.mk
|
||||
|
||||
# We want to check if `no-builtins` is also added to the function declarations in the used crate.
|
||||
|
||||
all:
|
||||
$(RUSTC) no_builtins.rs --emit=link
|
||||
$(RUSTC) main.rs --emit=llvm-ir
|
||||
|
||||
cat "$(TMPDIR)"/main.ll | "$(LLVM_FILECHECK)" filecheck.main.txt
|
5
tests/run-make/no-builtins-attribute/filecheck.main.txt
Normal file
5
tests/run-make/no-builtins-attribute/filecheck.main.txt
Normal file
@ -0,0 +1,5 @@
|
||||
CHECK: declare void @foo()
|
||||
CHECK-SAME: #[[ATTR_3:[0-9]+]]
|
||||
|
||||
CHECK: attributes #[[ATTR_3]]
|
||||
CHECK-SAME: no-builtins
|
10
tests/run-make/no-builtins-attribute/main.rs
Normal file
10
tests/run-make/no-builtins-attribute/main.rs
Normal file
@ -0,0 +1,10 @@
|
||||
extern crate no_builtins;
|
||||
|
||||
#[no_mangle]
|
||||
fn call_foo() {
|
||||
no_builtins::foo();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
call_foo();
|
||||
}
|
5
tests/run-make/no-builtins-attribute/no_builtins.rs
Normal file
5
tests/run-make/no-builtins-attribute/no_builtins.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![crate_type = "lib"]
|
||||
#![no_builtins]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn foo() {}
|
Loading…
x
Reference in New Issue
Block a user