Skip to content

Commit b52522a

Browse files
committed
Auto merge of #69749 - davidtwco:issue-46477-polymorphization, r=eddyb
Polymorphization This PR implements an analysis to detect when functions could remain polymorphic during code generation. Fixes #46477 r? @eddyb cc @rust-lang/wg-mir-opt @nikomatsakis @pnkfelix
2 parents 734233d + 4b99699 commit b52522a

Some content is hidden

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

67 files changed

+2034
-191
lines changed

src/librustc_codegen_llvm/callee.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use log::debug;
1313
use rustc_codegen_ssa::traits::*;
1414

1515
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
16-
use rustc_middle::ty::{Instance, TypeFoldable};
16+
use rustc_middle::ty::{self, Instance, TypeFoldable};
1717

1818
/// Codegens a reference to a fn/method item, monomorphizing and
1919
/// inlining as it goes.
@@ -29,14 +29,18 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
2929

3030
assert!(!instance.substs.needs_infer());
3131
assert!(!instance.substs.has_escaping_bound_vars());
32-
assert!(!instance.substs.has_param_types_or_consts());
3332

3433
if let Some(&llfn) = cx.instances.borrow().get(&instance) {
3534
return llfn;
3635
}
3736

3837
let sym = tcx.symbol_name(instance).name;
39-
debug!("get_fn({:?}: {:?}) => {}", instance, instance.monomorphic_ty(cx.tcx()), sym);
38+
debug!(
39+
"get_fn({:?}: {:?}) => {}",
40+
instance,
41+
instance.ty(cx.tcx(), ty::ParamEnv::reveal_all()),
42+
sym
43+
);
4044

4145
let fn_abi = FnAbi::of_instance(cx, instance, &[]);
4246

src/librustc_codegen_llvm/consts.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl CodegenCx<'ll, 'tcx> {
203203
def_id
204204
);
205205

206-
let ty = instance.monomorphic_ty(self.tcx);
206+
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
207207
let sym = self.tcx.symbol_name(instance).name;
208208

209209
debug!("get_static: sym={} instance={:?}", sym, instance);
@@ -361,7 +361,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
361361
};
362362

363363
let instance = Instance::mono(self.tcx, def_id);
364-
let ty = instance.monomorphic_ty(self.tcx);
364+
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
365365
let llty = self.layout_of(ty).llvm_type(self);
366366
let g = if val_llty == llty {
367367
g

src/librustc_codegen_llvm/debuginfo/metadata.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,8 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp
700700
prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
701701
.finalize(cx)
702702
}
703+
// Type parameters from polymorphized functions.
704+
ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
703705
_ => bug!("debuginfo: unexpected type in type_metadata: {:?}", t),
704706
};
705707

@@ -955,6 +957,20 @@ fn pointer_type_metadata(
955957
}
956958
}
957959

960+
fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
961+
debug!("param_type_metadata: {:?}", t);
962+
let name = format!("{:?}", t);
963+
return unsafe {
964+
llvm::LLVMRustDIBuilderCreateBasicType(
965+
DIB(cx),
966+
name.as_ptr().cast(),
967+
name.len(),
968+
Size::ZERO.bits(),
969+
DW_ATE_unsigned,
970+
)
971+
};
972+
}
973+
958974
pub fn compile_unit_metadata(
959975
tcx: TyCtxt<'_>,
960976
codegen_unit_name: &str,
@@ -2465,7 +2481,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
24652481
};
24662482

24672483
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
2468-
let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx);
2484+
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
24692485
let type_metadata = type_metadata(cx, variable_type, span);
24702486
let var_name = tcx.item_name(def_id).as_str();
24712487
let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;

src/librustc_codegen_llvm/debuginfo/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_index::vec::IndexVec;
2626
use rustc_middle::mir;
2727
use rustc_middle::ty::layout::HasTyCtxt;
2828
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
29-
use rustc_middle::ty::{self, Instance, ParamEnv, Ty};
29+
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
3030
use rustc_session::config::{self, DebugInfo};
3131
use rustc_span::symbol::Symbol;
3232
use rustc_span::{self, BytePos, Span};
@@ -470,7 +470,9 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
470470
match impl_self_ty.kind {
471471
ty::Adt(def, ..) if !def.is_box() => {
472472
// Again, only create type information if full debuginfo is enabled
473-
if cx.sess().opts.debuginfo == DebugInfo::Full {
473+
if cx.sess().opts.debuginfo == DebugInfo::Full
474+
&& !impl_self_ty.needs_subst()
475+
{
474476
Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
475477
} else {
476478
Some(namespace::item_namespace(cx, def.did))

src/librustc_codegen_llvm/intrinsic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
160160
caller_instance: ty::Instance<'tcx>,
161161
) {
162162
let tcx = self.tcx;
163-
let callee_ty = instance.monomorphic_ty(tcx);
163+
let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
164164

165165
let (def_id, substs) = match callee_ty.kind {
166166
ty::FnDef(def_id, substs) => (def_id, substs),

src/librustc_codegen_llvm/mono_item.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1010
pub use rustc_middle::mir::mono::MonoItem;
1111
use rustc_middle::mir::mono::{Linkage, Visibility};
1212
use rustc_middle::ty::layout::FnAbiExt;
13-
use rustc_middle::ty::{Instance, TypeFoldable};
13+
use rustc_middle::ty::{self, Instance, TypeFoldable};
1414
use rustc_target::abi::LayoutOf;
1515

1616
impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -22,7 +22,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
2222
symbol_name: &str,
2323
) {
2424
let instance = Instance::mono(self.tcx, def_id);
25-
let ty = instance.monomorphic_ty(self.tcx);
25+
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
2626
let llty = self.layout_of(ty).llvm_type(self);
2727

2828
let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
@@ -47,7 +47,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
4747
visibility: Visibility,
4848
symbol_name: &str,
4949
) {
50-
assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types_or_consts());
50+
assert!(!instance.substs.needs_infer());
5151

5252
let fn_abi = FnAbi::of_instance(self, instance, &[]);
5353
let lldecl = self.declare_fn(symbol_name, &fn_abi);

src/librustc_codegen_ssa/debuginfo/type_names.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,17 @@ pub fn push_debuginfo_type_name<'tcx>(
205205
tcx.def_key(def_id).disambiguated_data.disambiguator
206206
));
207207
}
208+
// Type parameters from polymorphized functions.
209+
ty::Param(_) => {
210+
output.push_str(&format!("{:?}", t));
211+
}
208212
ty::Error(_)
209213
| ty::Infer(_)
210214
| ty::Placeholder(..)
211215
| ty::Projection(..)
212216
| ty::Bound(..)
213217
| ty::Opaque(..)
214-
| ty::GeneratorWitness(..)
215-
| ty::Param(_) => {
218+
| ty::GeneratorWitness(..) => {
216219
bug!(
217220
"debuginfo: Trying to create type name for \
218221
unexpected type: {:?}",

src/librustc_codegen_ssa/meth.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
9494
def_id,
9595
substs,
9696
)
97-
.unwrap(),
97+
.unwrap()
98+
.polymorphize(cx.tcx()),
9899
)
99100
})
100101
});

src/librustc_codegen_ssa/mir/analyze.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
124124
let base_ty = self.fx.monomorphize(&base_ty);
125125

126126
// ZSTs don't require any actual memory access.
127-
let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty;
128-
let elem_ty = self.fx.monomorphize(&elem_ty);
127+
let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty;
129128
let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
130129
if cx.spanned_layout_of(elem_ty, span).is_zst() {
131130
return;

src/librustc_codegen_ssa/mir/block.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
543543
Some(
544544
ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs)
545545
.unwrap()
546-
.unwrap(),
546+
.unwrap()
547+
.polymorphize(bx.tcx()),
547548
),
548549
None,
549550
),

src/librustc_codegen_ssa/mir/rvalue.rs

+10-11
Original file line numberDiff line numberDiff line change
@@ -190,17 +190,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
190190
if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) {
191191
bug!("reifying a fn ptr that requires const arguments");
192192
}
193-
OperandValue::Immediate(
194-
bx.get_fn_addr(
195-
ty::Instance::resolve_for_fn_ptr(
196-
bx.tcx(),
197-
ty::ParamEnv::reveal_all(),
198-
def_id,
199-
substs,
200-
)
201-
.unwrap(),
202-
),
193+
let instance = ty::Instance::resolve_for_fn_ptr(
194+
bx.tcx(),
195+
ty::ParamEnv::reveal_all(),
196+
def_id,
197+
substs,
203198
)
199+
.unwrap()
200+
.polymorphize(bx.cx().tcx());
201+
OperandValue::Immediate(bx.get_fn_addr(instance))
204202
}
205203
_ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
206204
}
@@ -213,7 +211,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
213211
def_id,
214212
substs,
215213
ty::ClosureKind::FnOnce,
216-
);
214+
)
215+
.polymorphize(bx.cx().tcx());
217216
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
218217
}
219218
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),

src/librustc_data_structures/stable_hasher.rs

+9
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,15 @@ impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C>
469469
}
470470
}
471471

472+
impl<T, CTX> HashStable<CTX> for bit_set::FiniteBitSet<T>
473+
where
474+
T: HashStable<CTX> + bit_set::FiniteBitSetTy,
475+
{
476+
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
477+
self.0.hash_stable(hcx, hasher);
478+
}
479+
}
480+
472481
impl_stable_hash_via_hash!(::std::path::Path);
473482
impl_stable_hash_via_hash!(::std::path::PathBuf);
474483

src/librustc_feature/builtin_attrs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
568568
),
569569
rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)),
570570
rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)),
571+
rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)),
571572
rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)),
572573
rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")),
573574
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),

src/librustc_index/bit_set.rs

+135
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::fmt;
44
use std::iter;
55
use std::marker::PhantomData;
66
use std::mem;
7+
use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
78
use std::slice;
89

910
#[cfg(test)]
@@ -1001,3 +1002,137 @@ fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
10011002
let mask = 1 << (elem % WORD_BITS);
10021003
(word_index, mask)
10031004
}
1005+
1006+
/// Integral type used to represent the bit set.
1007+
pub trait FiniteBitSetTy:
1008+
BitAnd<Output = Self>
1009+
+ BitAndAssign
1010+
+ BitOrAssign
1011+
+ Clone
1012+
+ Copy
1013+
+ Shl
1014+
+ Not<Output = Self>
1015+
+ PartialEq
1016+
+ Sized
1017+
{
1018+
/// Size of the domain representable by this type, e.g. 64 for `u64`.
1019+
const DOMAIN_SIZE: u32;
1020+
1021+
/// Value which represents the `FiniteBitSet` having every bit set.
1022+
const FILLED: Self;
1023+
/// Value which represents the `FiniteBitSet` having no bits set.
1024+
const EMPTY: Self;
1025+
1026+
/// Value for one as the integral type.
1027+
const ONE: Self;
1028+
/// Value for zero as the integral type.
1029+
const ZERO: Self;
1030+
1031+
/// Perform a checked left shift on the integral type.
1032+
fn checked_shl(self, rhs: u32) -> Option<Self>;
1033+
/// Perform a checked right shift on the integral type.
1034+
fn checked_shr(self, rhs: u32) -> Option<Self>;
1035+
}
1036+
1037+
impl FiniteBitSetTy for u64 {
1038+
const DOMAIN_SIZE: u32 = 64;
1039+
1040+
const FILLED: Self = Self::MAX;
1041+
const EMPTY: Self = Self::MIN;
1042+
1043+
const ONE: Self = 1u64;
1044+
const ZERO: Self = 0u64;
1045+
1046+
fn checked_shl(self, rhs: u32) -> Option<Self> {
1047+
self.checked_shl(rhs)
1048+
}
1049+
1050+
fn checked_shr(self, rhs: u32) -> Option<Self> {
1051+
self.checked_shr(rhs)
1052+
}
1053+
}
1054+
1055+
impl std::fmt::Debug for FiniteBitSet<u64> {
1056+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1057+
write!(f, "{:064b}", self.0)
1058+
}
1059+
}
1060+
1061+
impl FiniteBitSetTy for u128 {
1062+
const DOMAIN_SIZE: u32 = 128;
1063+
1064+
const FILLED: Self = Self::MAX;
1065+
const EMPTY: Self = Self::MIN;
1066+
1067+
const ONE: Self = 1u128;
1068+
const ZERO: Self = 0u128;
1069+
1070+
fn checked_shl(self, rhs: u32) -> Option<Self> {
1071+
self.checked_shl(rhs)
1072+
}
1073+
1074+
fn checked_shr(self, rhs: u32) -> Option<Self> {
1075+
self.checked_shr(rhs)
1076+
}
1077+
}
1078+
1079+
impl std::fmt::Debug for FiniteBitSet<u128> {
1080+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1081+
write!(f, "{:0128b}", self.0)
1082+
}
1083+
}
1084+
1085+
/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
1086+
/// representable by `T` are considered set.
1087+
#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
1088+
pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
1089+
1090+
impl<T: FiniteBitSetTy> FiniteBitSet<T> {
1091+
/// Creates a new, empty bitset.
1092+
pub fn new_empty() -> Self {
1093+
Self(T::EMPTY)
1094+
}
1095+
1096+
/// Sets the `index`th bit.
1097+
pub fn set(&mut self, index: u32) {
1098+
self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO);
1099+
}
1100+
1101+
/// Unsets the `index`th bit.
1102+
pub fn clear(&mut self, index: u32) {
1103+
self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO);
1104+
}
1105+
1106+
/// Sets the `i`th to `j`th bits.
1107+
pub fn set_range(&mut self, range: Range<u32>) {
1108+
let bits = T::FILLED
1109+
.checked_shl(range.end - range.start)
1110+
.unwrap_or(T::ZERO)
1111+
.not()
1112+
.checked_shl(range.start)
1113+
.unwrap_or(T::ZERO);
1114+
self.0 |= bits;
1115+
}
1116+
1117+
/// Is the set empty?
1118+
pub fn is_empty(&self) -> bool {
1119+
self.0 == T::EMPTY
1120+
}
1121+
1122+
/// Returns the domain size of the bitset.
1123+
pub fn within_domain(&self, index: u32) -> bool {
1124+
index < T::DOMAIN_SIZE
1125+
}
1126+
1127+
/// Returns if the `index`th bit is set.
1128+
pub fn contains(&self, index: u32) -> Option<bool> {
1129+
self.within_domain(index)
1130+
.then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE)
1131+
}
1132+
}
1133+
1134+
impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
1135+
fn default() -> Self {
1136+
Self::new_empty()
1137+
}
1138+
}

0 commit comments

Comments
 (0)