about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2023-07-19 22:37:06 +0530
committerGitHub <noreply@github.com>2023-07-19 22:37:06 +0530
commitc1d6d322f424335c4bafaeb2e175561b353a185a (patch)
tree4750fbdbeb1cb41671144f3205adef74a7dc041d
parentc2257b94129ff39129f8f684244eaa961b720799 (diff)
parentcc08749df2613c17c8c2e9d8224a24a24c126423 (diff)
downloadrust-c1d6d322f424335c4bafaeb2e175561b353a185a.tar.gz
rust-c1d6d322f424335c4bafaeb2e175561b353a185a.zip
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?
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs10
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--tests/codegen/no_builtins-at-crate.rs24
-rw-r--r--tests/run-make/no-builtins-attribute/Makefile9
-rw-r--r--tests/run-make/no-builtins-attribute/filecheck.main.txt5
-rw-r--r--tests/run-make/no-builtins-attribute/main.rs10
-rw-r--r--tests/run-make/no-builtins-attribute/no_builtins.rs5
8 files changed, 68 insertions, 1 deletions
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 39275272e42..4c69b9503a2 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -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));
     }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index d6c23012762..0c7b8a79612 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -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;
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index c4601a1fb41..02fd6ed7ba6 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -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;
     }
 }
 
diff --git a/tests/codegen/no_builtins-at-crate.rs b/tests/codegen/no_builtins-at-crate.rs
new file mode 100644
index 00000000000..02ed670900e
--- /dev/null
+++ b/tests/codegen/no_builtins-at-crate.rs
@@ -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"
diff --git a/tests/run-make/no-builtins-attribute/Makefile b/tests/run-make/no-builtins-attribute/Makefile
new file mode 100644
index 00000000000..0ce95facaea
--- /dev/null
+++ b/tests/run-make/no-builtins-attribute/Makefile
@@ -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
diff --git a/tests/run-make/no-builtins-attribute/filecheck.main.txt b/tests/run-make/no-builtins-attribute/filecheck.main.txt
new file mode 100644
index 00000000000..ecd650bdca8
--- /dev/null
+++ b/tests/run-make/no-builtins-attribute/filecheck.main.txt
@@ -0,0 +1,5 @@
+CHECK: declare void @foo()
+CHECK-SAME: #[[ATTR_3:[0-9]+]]
+
+CHECK: attributes #[[ATTR_3]] 
+CHECK-SAME: no-builtins
diff --git a/tests/run-make/no-builtins-attribute/main.rs b/tests/run-make/no-builtins-attribute/main.rs
new file mode 100644
index 00000000000..77754b37e31
--- /dev/null
+++ b/tests/run-make/no-builtins-attribute/main.rs
@@ -0,0 +1,10 @@
+extern crate no_builtins;
+
+#[no_mangle]
+fn call_foo() {
+    no_builtins::foo();
+}
+
+fn main() {
+    call_foo();
+}
diff --git a/tests/run-make/no-builtins-attribute/no_builtins.rs b/tests/run-make/no-builtins-attribute/no_builtins.rs
new file mode 100644
index 00000000000..8ca862d2f77
--- /dev/null
+++ b/tests/run-make/no-builtins-attribute/no_builtins.rs
@@ -0,0 +1,5 @@
+#![crate_type = "lib"]
+#![no_builtins]
+
+#[no_mangle]
+pub fn foo() {}