Skip to content

Commit 7070de9

Browse files
committed
Auto merge of #157480 - nikic:captures-metadata, r=<try>
Set !captures metadata for store of &Freeze
2 parents 3179a47 + 41ee7f1 commit 7070de9

5 files changed

Lines changed: 109 additions & 6 deletions

File tree

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,18 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
854854
self.set_metadata_node(store, llvm::MD_nontemporal, &[one]);
855855
}
856856
}
857+
if flags.contains(MemFlags::CAPTURES_READ_ONLY)
858+
&& crate::llvm_util::get_version() >= (22, 0, 0)
859+
{
860+
let args = [
861+
self.cx.create_metadata(b"address"),
862+
self.cx.create_metadata(b"read_provenance"),
863+
];
864+
// FIXME: Switch this to use MD_captures once LLVM 22 is the minimum.
865+
let id = self.get_md_kind_id("captures");
866+
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, args.as_ptr(), args.len());
867+
self.set_metadata(store, id, md);
868+
}
857869
store
858870
}
859871
}

compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ bitflags::bitflags! {
167167
const VOLATILE = 1 << 0;
168168
const NONTEMPORAL = 1 << 1;
169169
const UNALIGNED = 1 << 2;
170+
const CAPTURES_READ_ONLY = 1 << 3;
170171
}
171172
}
172173

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
296296
self,
297297
bx: &mut Bx,
298298
dest: PlaceRef<'tcx, V>,
299+
) {
300+
self.store_with_annotation_and_flags(bx, dest, MemFlags::empty())
301+
}
302+
303+
/// Same as store_with_annotation(), but also specify flags for the store.
304+
pub fn store_with_annotation_and_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
305+
self,
306+
bx: &mut Bx,
307+
dest: PlaceRef<'tcx, V>,
308+
flags: MemFlags,
299309
) {
300310
if let Some(instance) = self.move_annotation {
301-
bx.with_move_annotation(instance, |bx| self.val.store(bx, dest))
311+
bx.with_move_annotation(instance, |bx| self.val.store_with_flags(bx, dest, flags))
302312
} else {
303-
self.val.store(bx, dest)
313+
self.val.store_with_flags(bx, dest, flags)
304314
}
305315
}
306316

@@ -961,7 +971,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
961971
let llptr = bx.inbounds_ptradd(dest.val.llval, bx.const_usize(b_offset.bytes()));
962972
let val = bx.from_immediate(b);
963973
let align = dest.val.align.restrict_for_offset(b_offset);
964-
bx.store_with_flags(val, llptr, align, flags);
974+
// The CAPTURES_READ_ONLY flag only applies to the first element.
975+
bx.store_with_flags(val, llptr, align, flags & !MemFlags::CAPTURES_READ_ONLY);
965976
}
966977
}
967978
}

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use itertools::Itertools as _;
22
use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT};
33
use rustc_middle::ty::adjustment::PointerCoercion;
44
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
5-
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
5+
use rustc_middle::ty::{self, Instance, Mutability, Ty, TyCtxt};
66
use rustc_middle::{bug, mir, span_bug};
77
use rustc_session::config::OptLevel;
88
use tracing::{debug, instrument};
@@ -23,7 +23,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2323
rvalue: &mir::Rvalue<'tcx>,
2424
) {
2525
match *rvalue {
26-
mir::Rvalue::Use(ref operand, _) => {
26+
mir::Rvalue::Use(ref operand, with_retag) => {
2727
if let mir::Operand::Constant(const_op) = operand {
2828
let val = self.eval_mir_constant(&const_op);
2929
if val.all_bytes_uninit(self.cx.tcx()) {
@@ -40,9 +40,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
4040
) {
4141
debug_assert!(!matches!(cg_operand.val, OperandValue::Ref(..)));
4242
}
43+
// If this is storing a &Freeze reference with a retag, record that it's not
44+
// possible to perform writes through the stored pointer.
45+
let flags = if let ty::Ref(_, pointee_ty, Mutability::Not) =
46+
operand.ty(self.mir, self.cx.tcx()).kind()
47+
&& with_retag.yes()
48+
&& pointee_ty.is_freeze(self.cx.tcx(), self.cx.typing_env())
49+
{
50+
MemFlags::CAPTURES_READ_ONLY
51+
} else {
52+
MemFlags::empty()
53+
};
4354
// FIXME: consider not copying constants through stack. (Fixable by codegen'ing
4455
// constants into `OperandValue::Ref`; why don’t we do that yet if we don’t?)
45-
cg_operand.store_with_annotation(bx, dest);
56+
cg_operand.store_with_annotation_and_flags(bx, dest, flags);
4657
}
4758

4859
mir::Rvalue::Cast(
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//@ min-llvm-version: 22
2+
//@ compile-flags: -O -C no-prepopulate-passes
3+
4+
#![crate_type = "lib"]
5+
6+
use std::cell::UnsafeCell;
7+
8+
#[unsafe(no_mangle)]
9+
pub fn store_ptr<'a>(x: *const i32, y: &mut *const i32) {
10+
// CHECK-LABEL: define void @store_ptr
11+
// CHECK-NOT: !captures
12+
*y = x;
13+
}
14+
15+
#[unsafe(no_mangle)]
16+
pub fn store_ref_freeze<'a>(x: &'a i32, y: &mut &'a i32) {
17+
// CHECK-LABEL: define void @store_ref_freeze
18+
// CHECK: store ptr %x, ptr %y, {{.*}}, !captures ![[CAPTURES:[0-9]+]]
19+
*y = x;
20+
}
21+
22+
#[unsafe(no_mangle)]
23+
pub fn store_ref_not_freeze<'a>(x: &'a UnsafeCell<i32>, y: &mut &'a UnsafeCell<i32>) {
24+
// CHECK-LABEL: define void @store_ref_not_freeze
25+
// CHECK-NOT: !captures
26+
*y = x;
27+
}
28+
29+
#[unsafe(no_mangle)]
30+
pub fn store_mut_ref<'a>(x: &'a mut i32, y: &mut &'a mut i32) {
31+
// CHECK-LABEL: define void @store_mut_ref
32+
// CHECK-NOT: !captures
33+
*y = x;
34+
}
35+
36+
#[unsafe(no_mangle)]
37+
pub fn store_mut_ref_as_shared_ref<'a>(x: &'a mut i32, y: &mut &'a i32) {
38+
// CHECK-LABEL: define void @store_mut_ref_as_shared_ref
39+
// CHECK: store ptr %x, ptr %y, {{.*}}, !captures ![[CAPTURES:[0-9]+]]
40+
*y = x;
41+
}
42+
43+
#[unsafe(no_mangle)]
44+
pub fn store_mut_ref_as_ptr(x: &mut i32, y: &mut *const i32) {
45+
// CHECK-LABEL: define void @store_mut_ref_as_ptr
46+
// CHECK-NOT: !captures
47+
*y = x;
48+
}
49+
50+
#[unsafe(no_mangle)]
51+
pub fn store_slice<'a>(x: &'a [i32], y: &mut &'a [i32]) {
52+
// CHECK-LABEL: define void @store_slice
53+
// CHECK: store ptr %x.0, ptr %y, {{.*}}, !captures ![[CAPTURES:[0-9]+]]
54+
// Second store is slice size, can't have !captures
55+
// CHECK-NOT: !captures
56+
*y = x;
57+
}
58+
59+
#[unsafe(no_mangle)]
60+
pub fn store_dyn<'a>(x: &'a dyn Drop, y: &mut &'a dyn Drop) {
61+
// dyn trait is not known Freeze. The vtable could use !captures,
62+
// but that's probably not particularly useful.
63+
// CHECK-LABEL: define void @store_dyn
64+
// CHECK-NOT: !captures
65+
*y = x;
66+
}
67+
68+
// CHECK: ![[CAPTURES]] = !{!"address", !"read_provenance"}

0 commit comments

Comments
 (0)