Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute generator sizes with -Zprint_type_sizes #104019

Merged
merged 4 commits into from
Dec 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 1 addition & 67 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_fs_util::path_to_c_string;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::bug;
use rustc_middle::mir::{self, GeneratorLayout};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{
Expand Down Expand Up @@ -1026,33 +1024,6 @@ fn build_struct_type_di_node<'ll, 'tcx>(
// Tuples
//=-----------------------------------------------------------------------------

/// Returns names of captured upvars for closures and generators.
///
/// Here are some examples:
/// - `name__field1__field2` when the upvar is captured by value.
/// - `_ref__name__field` when the upvar is captured by reference.
///
/// For generators this only contains upvars that are shared by all states.
fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'_>, def_id: DefId) -> SmallVec<String> {
let body = tcx.optimized_mir(def_id);

body.var_debug_info
.iter()
.filter_map(|var| {
let is_ref = match var.value {
mir::VarDebugInfoContents::Place(place) if place.local == mir::Local::new(1) => {
// The projection is either `[.., Field, Deref]` or `[.., Field]`. It
// implies whether the variable is captured by value or by reference.
matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
}
_ => return None,
};
let prefix = if is_ref { "_ref__" } else { "" };
Some(prefix.to_owned() + var.name.as_str())
})
.collect()
}

/// Builds the DW_TAG_member debuginfo nodes for the upvars of a closure or generator.
/// For a generator, this will handle upvars shared by all states.
fn build_upvar_field_di_nodes<'ll, 'tcx>(
Expand Down Expand Up @@ -1083,7 +1054,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
.all(|&t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
);

let capture_names = closure_saved_names_of_captured_variables(cx.tcx, def_id);
let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
let layout = cx.layout_of(closure_or_generator_ty);

up_var_tys
Expand Down Expand Up @@ -1229,43 +1200,6 @@ fn build_union_type_di_node<'ll, 'tcx>(
)
}

// FIXME(eddyb) maybe precompute this? Right now it's computed once
// per generator monomorphization, but it doesn't depend on substs.
fn generator_layout_and_saved_local_names<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) {
let body = tcx.optimized_mir(def_id);
let generator_layout = body.generator_layout().unwrap();
let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);

let state_arg = mir::Local::new(1);
for var in &body.var_debug_info {
let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
if place.local != state_arg {
continue;
}
match place.projection[..] {
[
// Deref of the `Pin<&mut Self>` state argument.
mir::ProjectionElem::Field(..),
mir::ProjectionElem::Deref,
// Field of a variant of the state.
mir::ProjectionElem::Downcast(_, variant),
mir::ProjectionElem::Field(field, _),
] => {
let name = &mut generator_saved_local_names
[generator_layout.variant_fields[variant][field]];
if name.is_none() {
name.replace(var.name);
}
}
_ => {}
}
}
(generator_layout, generator_saved_local_names)
}

/// Computes the type parameters for a type, if any, for the given metadata.
fn build_generic_type_param_di_nodes<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ use crate::{
common::CodegenCx,
debuginfo::{
metadata::{
build_field_di_node, closure_saved_names_of_captured_variables,
build_field_di_node,
enums::{tag_base_type, DiscrResult},
file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node,
file_metadata, size_and_align_of, type_di_node,
type_map::{self, Stub, UniqueTypeId},
unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA,
UNKNOWN_LINE_NUMBER,
Expand Down Expand Up @@ -677,9 +677,9 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
};

let (generator_layout, state_specific_upvar_names) =
generator_layout_and_saved_local_names(cx.tcx, generator_def_id);
cx.tcx.generator_layout_and_saved_local_names(generator_def_id);

let common_upvar_names = closure_saved_names_of_captured_variables(cx.tcx, generator_def_id);
let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(generator_def_id);
let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx);
let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use crate::{
common::CodegenCx,
debuginfo::{
metadata::{
closure_saved_names_of_captured_variables,
enums::tag_base_type,
file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node,
file_metadata, size_and_align_of, type_di_node,
type_map::{self, Stub, StubInfo, UniqueTypeId},
unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS,
UNKNOWN_LINE_NUMBER,
Expand Down Expand Up @@ -157,7 +156,7 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>(
),
|cx, generator_type_di_node| {
let (generator_layout, state_specific_upvar_names) =
generator_layout_and_saved_local_names(cx.tcx, generator_def_id);
cx.tcx.generator_layout_and_saved_local_names(generator_def_id);

let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = generator_type_and_layout.variants else {
bug!(
Expand All @@ -167,7 +166,7 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>(
};

let common_upvar_names =
closure_saved_names_of_captured_variables(cx.tcx, generator_def_id);
cx.tcx.closure_saved_names_of_captured_variables(generator_def_id);

// Build variant struct types
let variant_struct_type_di_nodes: SmallVec<_> = variants
Expand Down
76 changes: 76 additions & 0 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Miscellaneous type-system utilities that are too small to deserve their own modules.

use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir;
use crate::ty::layout::IntegerExt;
use crate::ty::{
self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
Expand All @@ -15,6 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::GrowableBitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_span::{sym, DUMMY_SP};
use rustc_target::abi::{Integer, IntegerType, Size, TargetDataLayout};
Expand Down Expand Up @@ -692,6 +694,80 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
ty::EarlyBinder(self.impl_subject(def_id))
}

/// Returns names of captured upvars for closures and generators.
///
/// Here are some examples:
/// - `name__field1__field2` when the upvar is captured by value.
/// - `_ref__name__field` when the upvar is captured by reference.
///
/// For generators this only contains upvars that are shared by all states.
pub fn closure_saved_names_of_captured_variables(
self,
def_id: DefId,
) -> SmallVec<[String; 16]> {
let body = self.optimized_mir(def_id);

body.var_debug_info
.iter()
.filter_map(|var| {
let is_ref = match var.value {
mir::VarDebugInfoContents::Place(place)
if place.local == mir::Local::new(1) =>
{
// The projection is either `[.., Field, Deref]` or `[.., Field]`. It
// implies whether the variable is captured by value or by reference.
matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
}
_ => return None,
};
let prefix = if is_ref { "_ref__" } else { "" };
Some(prefix.to_owned() + var.name.as_str())
})
.collect()
}

// FIXME(eddyb) maybe precompute this? Right now it's computed once
// per generator monomorphization, but it doesn't depend on substs.
pub fn generator_layout_and_saved_local_names(
self,
def_id: DefId,
) -> (
&'tcx ty::GeneratorLayout<'tcx>,
IndexVec<mir::GeneratorSavedLocal, Option<rustc_span::Symbol>>,
) {
let tcx = self;
let body = tcx.optimized_mir(def_id);
let generator_layout = body.generator_layout().unwrap();
let mut generator_saved_local_names =
IndexVec::from_elem(None, &generator_layout.field_tys);

let state_arg = mir::Local::new(1);
for var in &body.var_debug_info {
let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
if place.local != state_arg {
continue;
}
match place.projection[..] {
[
// Deref of the `Pin<&mut Self>` state argument.
mir::ProjectionElem::Field(..),
mir::ProjectionElem::Deref,
// Field of a variant of the state.
mir::ProjectionElem::Downcast(_, variant),
mir::ProjectionElem::Field(field, _),
] => {
let name = &mut generator_saved_local_names
[generator_layout.variant_fields[variant][field]];
if name.is_none() {
name.replace(var.name);
}
}
_ => {}
}
}
(generator_layout, generator_saved_local_names)
}
}

struct OpaqueTypeExpander<'tcx> {
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_session/src/code_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum SizeKind {
Min,
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FieldInfo {
pub name: Symbol,
pub offset: u64,
Expand All @@ -33,6 +33,7 @@ pub enum DataTypeKind {
Union,
Enum,
Closure,
Generator,
}

#[derive(PartialEq, Eq, Hash, Debug)]
Expand Down Expand Up @@ -114,7 +115,7 @@ impl CodeStats {

let struct_like = match kind {
DataTypeKind::Struct | DataTypeKind::Closure => true,
DataTypeKind::Enum | DataTypeKind::Union => false,
DataTypeKind::Enum | DataTypeKind::Union | DataTypeKind::Generator => false,
};
for (i, variant_info) in variants.into_iter().enumerate() {
let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
Expand Down
Loading