diff --git a/src/backend/monomorph.md b/src/backend/monomorph.md index 5e5d2e0c4..47b41d4f6 100644 --- a/src/backend/monomorph.md +++ b/src/backend/monomorph.md @@ -61,33 +61,73 @@ units](../appendix/glossary.md#codegen-unit). ## Polymorphization As mentioned above, monomorphization produces fast code, but it comes at the -cost of compile time and binary size. [MIR -optimizations](../mir/optimizations.md) can help a bit with this. Another -optimization currently under development is called _polymorphization_. - -The general idea is that often we can share some code between monomorphized -copies of code. More precisely, if a MIR block is not dependent on a type -parameter, it may not need to be monomorphized into many copies. Consider the -following example: +cost of compile time and binary size. [MIR optimizations][miropt] can help a +bit with this. + +In addition to MIR optimizations, rustc attempts to determine when fewer +copies of functions are necessary and avoid making those copies - known +as "polymorphization". When a function-like item is found during +monomorphization collection, the +[`rustc_mir::monomorphize::polymorphize::unused_generic_params`][polymorph] +query is invoked, which traverses the MIR of the item to determine on which +generic parameters the item might not need duplicated. + +Currently, polymorphization only looks for unused generic parameters. These +are relatively rare in functions, but closures inherit the generic +parameters of their parent function and it is common for closures to not +use those inherited parameters. Without polymorphization, a copy of these +closures would be created for each copy of the parent function. By +creating fewer copies, less LLVM IR is generated and needs processed. + +`unused_generic_params` returns a `FiniteBitSet` where a bit is set if +the generic parameter of the corresponding index is unused. Any parameters +after the first sixty-four are considered used. + +The results of polymorphization analysis are used in the +[`Instance::polymorphize`][inst_polymorph] function to replace the +[`Instance`][inst]'s substitutions for the unused generic parameters with their +identity substitutions. + +Consider the example below: ```rust -pub fn f() { - g::(); - g::(); +fn foo() { + let x: Option = None; } -fn g() -> usize { - let n = 1; - let closure = || n; - closure() +fn main() { + foo::(); + foo::(); } ``` -In this case, we would currently collect `[f, g::, g::, -g::::{{closure}}, g::::{{closure}}]`, but notice that the two -closures would be identical -- they don't depend on the type parameter `T` of -function `g`. So we only need to emit one copy of the closure. +During monomorphization collection, `foo` will be collected with the +substitutions `[u16, u32]` and `[u64, u32]` (from its invocations in `main`). +`foo` has the identity substitutions `[A, B]` (or +`[ty::Param(0), ty::Param(1)]`). + +Polymorphization will identify `A` as being unused and it will be replaced in +the substitutions with the identity parameter before being added to the set +of collected items - thereby reducing the copies from two (`[u16, u32]` and +`[u64, u32]`) to one (`[A, u32]`). + +`unused_generic_params` will also invoked during code generation when the +symbol name for `foo` is being computed for use in the callsites of `foo` +(which have the regular substitutions present, otherwise there would be a +symbol mismatch between the caller and the function). + +As a result of polymorphization, items collected during monomorphization +cannot be assumed to be monomorphic. + +It is intended that polymorphization be extended to more advanced cases, +such as where only the size/alignment of a generic parameter are required. -For more information, see [this thread on github][polymorph]. +More details on polymorphization are available in the +[master's thesis][thesis] associated with polymorphization's initial +implementation. -[polymorph]: https://github.com/rust-lang/rust/issues/46477 +[miropt]: ../mir/optimizations.md +[polymorph]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/monomorphize/polymorphize/fn.unused_generic_params.html +[inst]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/instance/struct.Instance.html +[inst_polymorph]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/instance/struct.Instance.html#method.polymorphize +[thesis]: https://davidtw.co/media/masters_dissertation.pdf