Skip to content

Commit 6081b49

Browse files
Codegen ZSTs without an allocation
This makes sure that &[] is just as efficient as indirecting through unsafe code (from_raw_parts). No new stable guarantee is intended about whether or not we do this, this is just an optimization.
1 parent a8a88fe commit 6081b49

File tree

2 files changed

+44
-22
lines changed

2 files changed

+44
-22
lines changed

Diff for: compiler/rustc_codegen_llvm/src/common.rs

+31-14
Original file line numberDiff line numberDiff line change
@@ -255,21 +255,38 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
255255
let (prov, offset) = ptr.into_parts();
256256
let (base_addr, base_addr_space) = match self.tcx.global_alloc(prov.alloc_id()) {
257257
GlobalAlloc::Memory(alloc) => {
258-
let init = const_alloc_to_llvm(self, alloc);
259-
let alloc = alloc.inner();
260-
let value = match alloc.mutability {
261-
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
262-
_ => self.static_addr_of(init, alloc.align, None),
263-
};
264-
if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() {
265-
let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
266-
let mut hasher = StableHasher::new();
267-
alloc.hash_stable(&mut hcx, &mut hasher);
268-
hasher.finish::<Hash128>()
269-
});
270-
llvm::set_value_name(value, format!("alloc_{hash:032x}").as_bytes());
258+
// For ZSTs directly codegen an aligned pointer.
259+
// This avoids generating a zero-sized constant value and actually needing a
260+
// real address at runtime.
261+
if alloc.inner().len() == 0 {
262+
assert_eq!(offset.bytes(), 0);
263+
let llval = self.const_usize(alloc.inner().align.bytes());
264+
return if matches!(layout.primitive(), Pointer(_)) {
265+
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
266+
} else {
267+
self.const_bitcast(llval, llty)
268+
};
269+
} else {
270+
let init = const_alloc_to_llvm(self, alloc);
271+
let alloc = alloc.inner();
272+
let value = match alloc.mutability {
273+
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
274+
_ => self.static_addr_of(init, alloc.align, None),
275+
};
276+
if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty()
277+
{
278+
let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
279+
let mut hasher = StableHasher::new();
280+
alloc.hash_stable(&mut hcx, &mut hasher);
281+
hasher.finish::<Hash128>()
282+
});
283+
llvm::set_value_name(
284+
value,
285+
format!("alloc_{hash:032x}").as_bytes(),
286+
);
287+
}
288+
(value, AddressSpace::DATA)
271289
}
272-
(value, AddressSpace::DATA)
273290
}
274291
GlobalAlloc::Function(fn_instance) => (
275292
self.get_fn_addr(fn_instance.polymorphize(self.tcx)),

Diff for: tests/ui/consts/zst_no_llvm_alloc.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ struct Foo;
66
static FOO: Foo = Foo;
77

88
fn main() {
9+
// There's no stable guarantee that these are true.
10+
// However, we want them to be true so that our LLVM IR and runtime are a bit faster:
11+
// a constant address is cheap and doesn't result in relocations in comparison to a "real"
12+
// global somewhere in the data section.
913
let x: &'static () = &();
10-
assert_ne!(x as *const () as usize, 1);
14+
assert_eq!(x as *const () as usize, 1);
1115
let x: &'static Foo = &Foo;
12-
assert_ne!(x as *const Foo as usize, 4);
16+
assert_eq!(x as *const Foo as usize, 4);
1317

14-
// statics must have a unique address
15-
assert_ne!(&FOO as *const Foo as usize, 4);
18+
// The exact addresses returned by these library functions are not necessarily stable guarantees
19+
// but for now we assert that we're still matching.
20+
assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
21+
assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
1622

17-
// FIXME this two tests should be assert_eq!
18-
// this stopped working since we are promoting to constants instead of statics
19-
assert_ne!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
20-
assert_ne!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
23+
// statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
24+
// clear whether this is a stable guarantee)
25+
assert_ne!(&FOO as *const Foo as usize, 4);
2126
}

0 commit comments

Comments
 (0)