Skip to content

Commit ee17466

Browse files
committed
Auto merge of rust-lang#121644 - oli-obk:unique_static_innards2, r=<try>
Ensure nested allocations in statics do not get deduplicated This PR generates new `DefId`s for nested allocations in static items and feeds all the right queries to make the compiler believe these are regular `static` items. I chose this design, because all other designs are fragile and make the compiler horribly complex for such a niche use case. At present this wrecks incremental compilation performance *in case nested allocations exist* (because any query creating a `DefId` will be recomputed and never loaded from the cache). This will be resolved later in rust-lang#115613 . All other statics are unaffected by this change and will not have performance regressions (heh, famous last words) This PR contains various smaller refactorings that can be pulled out into separate PRs. It is best reviewed commit-by-commit. The last commit is where the actual magic happens. r? `@RalfJung` on the const interner and engine changes fixes rust-lang#79738
2 parents fc3800f + e5836ab commit ee17466

File tree

66 files changed

+423
-166
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+423
-166
lines changed

compiler/rustc_ast_lowering/src/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
195195
.get_partial_res(sym.id)
196196
.and_then(|res| res.full_res())
197197
.and_then(|res| match res {
198-
Res::Def(DefKind::Static(_), def_id) => Some(def_id),
198+
Res::Def(DefKind::Static { .. }, def_id) => Some(def_id),
199199
_ => None,
200200
});
201201

compiler/rustc_codegen_gcc/src/consts.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
5555
global_value
5656
}
5757

58-
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
58+
fn codegen_static(&self, def_id: DefId) {
5959
let attrs = self.tcx.codegen_fn_attrs(def_id);
6060

6161
let value =
@@ -89,7 +89,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
8989

9090
// As an optimization, all shared statics which do not have interior
9191
// mutability are placed into read-only memory.
92-
if !is_mutable {
92+
if !self.tcx.static_mutability(def_id).unwrap().is_mut() {
9393
if self.type_is_freeze(ty) {
9494
#[cfg(feature = "master")]
9595
global.global_set_readonly();
@@ -337,7 +337,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
337337
cx.const_struct(&llvals, true)
338338
}
339339

340-
pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
340+
fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
341341
let alloc = cx.tcx.eval_static_initializer(def_id)?;
342342
Ok((const_alloc_to_gcc(cx, alloc), alloc))
343343
}

compiler/rustc_codegen_gcc/src/mono_item.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use gccjit::{VarAttribute, FnAttribute};
33
use rustc_codegen_ssa::traits::PreDefineMethods;
44
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
55
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
6+
use rustc_middle::bug;
67
use rustc_middle::mir::mono::{Linkage, Visibility};
78
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
89
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
10+
use rustc_hir::def::DefKind;
911

1012
use crate::attributes;
1113
use crate::base;
@@ -17,7 +19,10 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
1719
fn predefine_static(&self, def_id: DefId, _linkage: Linkage, visibility: Visibility, symbol_name: &str) {
1820
let attrs = self.tcx.codegen_fn_attrs(def_id);
1921
let instance = Instance::mono(self.tcx, def_id);
20-
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
22+
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
23+
// Nested statics do not have a type, so pick a random type and let `define_static` figure out
24+
// the llvm type from the actual evaluated initializer.
25+
let ty = if nested { self.tcx.types.unit} else { instance.ty(self.tcx, ty::ParamEnv::reveal_all()) };
2126
let gcc_type = self.layout_of(ty).gcc_type(self);
2227

2328
let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);

compiler/rustc_codegen_llvm/src/consts.rs

+63-41
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::type_::Type;
99
use crate::type_of::LayoutLlvmExt;
1010
use crate::value::Value;
1111
use rustc_codegen_ssa::traits::*;
12+
use rustc_hir::def::DefKind;
1213
use rustc_hir::def_id::DefId;
1314
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
1415
use rustc_middle::mir::interpret::{
@@ -17,7 +18,7 @@ use rustc_middle::mir::interpret::{
1718
};
1819
use rustc_middle::mir::mono::MonoItem;
1920
use rustc_middle::ty::layout::LayoutOf;
20-
use rustc_middle::ty::{self, Instance, Ty};
21+
use rustc_middle::ty::{self, Instance};
2122
use rustc_middle::{bug, span_bug};
2223
use rustc_session::config::Lto;
2324
use rustc_target::abi::{
@@ -114,7 +115,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
114115
cx.const_struct(&llvals, true)
115116
}
116117

117-
pub fn codegen_static_initializer<'ll, 'tcx>(
118+
fn codegen_static_initializer<'ll, 'tcx>(
118119
cx: &CodegenCx<'ll, 'tcx>,
119120
def_id: DefId,
120121
) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
@@ -147,11 +148,10 @@ fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align:
147148
fn check_and_apply_linkage<'ll, 'tcx>(
148149
cx: &CodegenCx<'ll, 'tcx>,
149150
attrs: &CodegenFnAttrs,
150-
ty: Ty<'tcx>,
151+
llty: &'ll Type,
151152
sym: &str,
152153
def_id: DefId,
153154
) -> &'ll Value {
154-
let llty = cx.layout_of(ty).llvm_type(cx);
155155
if let Some(linkage) = attrs.import_linkage {
156156
debug!("get_static: sym={} linkage={:?}", sym, linkage);
157157

@@ -226,9 +226,28 @@ impl<'ll> CodegenCx<'ll, '_> {
226226
}
227227
}
228228

229+
#[instrument(level = "debug", skip(self))]
229230
pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
230231
let instance = Instance::mono(self.tcx, def_id);
231-
if let Some(&g) = self.instances.borrow().get(&instance) {
232+
trace!(?instance);
233+
234+
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
235+
// Nested statics do not have a type, so pick a random type and let `define_static` figure out
236+
// the llvm type from the actual evaluated initializer.
237+
let llty = if nested {
238+
self.type_i8()
239+
} else {
240+
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
241+
trace!(?ty);
242+
self.layout_of(ty).llvm_type(self)
243+
};
244+
self.get_static_inner(def_id, llty)
245+
}
246+
247+
#[instrument(level = "debug", skip(self, llty))]
248+
pub(crate) fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value {
249+
if let Some(&g) = self.statics.borrow().get(&def_id) {
250+
trace!("used cached value");
232251
return g;
233252
}
234253

@@ -240,14 +259,12 @@ impl<'ll> CodegenCx<'ll, '_> {
240259
statics defined in the same CGU, but did not for `{def_id:?}`"
241260
);
242261

243-
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
244-
let sym = self.tcx.symbol_name(instance).name;
262+
let sym = self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name;
245263
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
246264

247-
debug!("get_static: sym={} instance={:?} fn_attrs={:?}", sym, instance, fn_attrs);
265+
debug!(?sym, ?fn_attrs);
248266

249267
let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
250-
let llty = self.layout_of(ty).llvm_type(self);
251268
if let Some(g) = self.get_declared_value(sym) {
252269
if self.val_ty(g) != self.type_ptr() {
253270
span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
@@ -264,7 +281,7 @@ impl<'ll> CodegenCx<'ll, '_> {
264281

265282
g
266283
} else {
267-
check_and_apply_linkage(self, fn_attrs, ty, sym, def_id)
284+
check_and_apply_linkage(self, fn_attrs, llty, sym, def_id)
268285
};
269286

270287
// Thread-local statics in some other crate need to *always* be linked
@@ -332,34 +349,15 @@ impl<'ll> CodegenCx<'ll, '_> {
332349
}
333350
}
334351

335-
self.instances.borrow_mut().insert(instance, g);
352+
self.statics.borrow_mut().insert(def_id, g);
336353
g
337354
}
338-
}
339-
340-
impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
341-
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
342-
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
343-
unsafe {
344-
// Upgrade the alignment in cases where the same constant is used with different
345-
// alignment requirements
346-
let llalign = align.bytes() as u32;
347-
if llalign > llvm::LLVMGetAlignment(gv) {
348-
llvm::LLVMSetAlignment(gv, llalign);
349-
}
350-
}
351-
return gv;
352-
}
353-
let gv = self.static_addr_of_mut(cv, align, kind);
354-
unsafe {
355-
llvm::LLVMSetGlobalConstant(gv, True);
356-
}
357-
self.const_globals.borrow_mut().insert(cv, gv);
358-
gv
359-
}
360355

361-
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
356+
fn codegen_static_item(&self, def_id: DefId) {
362357
unsafe {
358+
assert!(
359+
llvm::LLVMGetInitializer(self.statics.borrow().get(&def_id).unwrap()).is_none()
360+
);
363361
let attrs = self.tcx.codegen_fn_attrs(def_id);
364362

365363
let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else {
@@ -368,13 +366,11 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
368366
};
369367
let alloc = alloc.inner();
370368

371-
let g = self.get_static(def_id);
372-
373369
let val_llty = self.val_ty(v);
374370

375-
let instance = Instance::mono(self.tcx, def_id);
376-
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
377-
let llty = self.layout_of(ty).llvm_type(self);
371+
let g = self.get_static_inner(def_id, val_llty);
372+
let llty = self.val_ty(g);
373+
378374
let g = if val_llty == llty {
379375
g
380376
} else {
@@ -409,7 +405,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
409405
self.statics_to_rauw.borrow_mut().push((g, new_g));
410406
new_g
411407
};
412-
set_global_alignment(self, g, self.align_of(ty));
408+
set_global_alignment(self, g, alloc.align);
413409
llvm::LLVMSetInitializer(g, v);
414410

415411
if self.should_assume_dso_local(g, true) {
@@ -418,7 +414,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
418414

419415
// As an optimization, all shared statics which do not have interior
420416
// mutability are placed into read-only memory.
421-
if !is_mutable && self.type_is_freeze(ty) {
417+
if !self.tcx.is_mutable_static(def_id) && alloc.mutability.is_not() {
422418
llvm::LLVMSetGlobalConstant(g, llvm::True);
423419
}
424420

@@ -541,6 +537,32 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
541537
}
542538
}
543539
}
540+
}
541+
542+
impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
543+
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
544+
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
545+
unsafe {
546+
// Upgrade the alignment in cases where the same constant is used with different
547+
// alignment requirements
548+
let llalign = align.bytes() as u32;
549+
if llalign > llvm::LLVMGetAlignment(gv) {
550+
llvm::LLVMSetAlignment(gv, llalign);
551+
}
552+
}
553+
return gv;
554+
}
555+
let gv = self.static_addr_of_mut(cv, align, kind);
556+
unsafe {
557+
llvm::LLVMSetGlobalConstant(gv, True);
558+
}
559+
self.const_globals.borrow_mut().insert(cv, gv);
560+
gv
561+
}
562+
563+
fn codegen_static(&self, def_id: DefId) {
564+
self.codegen_static_item(def_id)
565+
}
544566

545567
/// Add a global value to a list to be stored in the `llvm.used` variable, an array of ptr.
546568
fn add_used_global(&self, global: &'ll Value) {

compiler/rustc_codegen_llvm/src/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ pub struct CodegenCx<'ll, 'tcx> {
5454

5555
/// Cache instances of monomorphic and polymorphic items
5656
pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
57+
58+
/// Cache static's allocations
59+
pub statics: RefCell<FxHashMap<DefId, &'ll Value>>,
5760
/// Cache generated vtables
5861
pub vtables:
5962
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
@@ -467,6 +470,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
467470
llcx,
468471
codegen_unit,
469472
instances: Default::default(),
473+
statics: Default::default(),
470474
vtables: Default::default(),
471475
const_str_cache: Default::default(),
472476
const_globals: Default::default(),

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
2626
use rustc_codegen_ssa::traits::*;
2727
use rustc_fs_util::path_to_c_string;
2828
use rustc_hir::def::CtorKind;
29+
use rustc_hir::def::DefKind;
2930
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
3031
use rustc_middle::bug;
3132
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
@@ -1301,7 +1302,12 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo
13011302
};
13021303

13031304
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
1304-
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
1305+
1306+
let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() };
1307+
if nested {
1308+
return;
1309+
}
1310+
let variable_type = cx.tcx.type_of(def_id).instantiate_identity();
13051311
let type_di_node = type_di_node(cx, variable_type);
13061312
let var_name = tcx.item_name(def_id);
13071313
let var_name = var_name.as_str();

compiler/rustc_codegen_llvm/src/mono_item.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use crate::errors::SymbolAlreadyDefined;
55
use crate::llvm;
66
use crate::type_of::LayoutLlvmExt;
77
use rustc_codegen_ssa::traits::*;
8+
use rustc_hir::def::DefKind;
89
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
10+
use rustc_middle::bug;
911
use rustc_middle::mir::mono::{Linkage, Visibility};
1012
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
1113
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
@@ -21,7 +23,14 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
2123
symbol_name: &str,
2224
) {
2325
let instance = Instance::mono(self.tcx, def_id);
24-
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
26+
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
27+
// Nested statics do not have a type, so pick a random type and let `define_static` figure out
28+
// the llvm type from the actual evaluated initializer.
29+
let ty = if nested {
30+
self.tcx.types.unit
31+
} else {
32+
instance.ty(self.tcx, ty::ParamEnv::reveal_all())
33+
};
2534
let llty = self.layout_of(ty).llvm_type(self);
2635

2736
let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
@@ -38,7 +47,7 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
3847
}
3948
}
4049

41-
self.instances.borrow_mut().insert(instance, g);
50+
self.statics.borrow_mut().insert(def_id, g);
4251
}
4352

4453
fn predefine_fn(

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
8383

8484
// Only consider nodes that actually have exported symbols.
8585
match tcx.def_kind(def_id) {
86-
DefKind::Fn | DefKind::Static(_) => {}
86+
DefKind::Fn | DefKind::Static { .. } => {}
8787
DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
8888
_ => return None,
8989
};
@@ -479,7 +479,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
479479
let target = &tcx.sess.target.llvm_target;
480480
// WebAssembly cannot export data symbols, so reduce their export level
481481
if target.contains("emscripten") {
482-
if let DefKind::Static(_) = tcx.def_kind(sym_def_id) {
482+
if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) {
483483
return SymbolExportLevel::Rust;
484484
}
485485
}

compiler/rustc_codegen_ssa/src/mono_item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
3030

3131
match *self {
3232
MonoItem::Static(def_id) => {
33-
cx.codegen_static(def_id, cx.tcx().is_mutable_static(def_id));
33+
cx.codegen_static(def_id);
3434
}
3535
MonoItem::GlobalAsm(item_id) => {
3636
let item = cx.tcx().hir().item(item_id);

compiler/rustc_codegen_ssa/src/traits/statics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_target::abi::Align;
44

55
pub trait StaticMethods: BackendTypes {
66
fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
7-
fn codegen_static(&self, def_id: DefId, is_mutable: bool);
7+
fn codegen_static(&self, def_id: DefId);
88

99
/// Mark the given global value as "used", to prevent the compiler and linker from potentially
1010
/// removing a static variable that may otherwise appear unused.

0 commit comments

Comments
 (0)