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

[WIP] Deduplicate instances #48139

Closed
wants to merge 21 commits into from
Closed

Conversation

bjorn3
Copy link
Member

@bjorn3 bjorn3 commented Feb 11, 2018

Fixes #46477

TODO:

  • Check if I didnt miss a place where TyParam is used (edit: I think I didn't have missed any of them)
  • Remove debug code
  • Fix debuginfo
  • Add tests

@rust-highfive
Copy link
Collaborator

r? @nikomatsakis

(rust_highfive has picked a reviewer for you, use r? to override)

@pietroalbini pietroalbini added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 11, 2018
@nikomatsakis
Copy link
Contributor

@bjorn3 can you give me a bit more context of what this PR is trying to achieve?

@bjorn3
Copy link
Member Author

bjorn3 commented Feb 13, 2018

This is trying to prevent duplicate instantiations of generic functions when there are generics which dont matter for codegen. For example:

fn abc<T>() {
    println!("djfjfjfb");
}

fn main() {
    abc::<()>();
    abc::<u8>();
}

This used to instantiate both abc::<()> and abc::() before this pr and just abc::<{some replacement}> with this pr.

@nikomatsakis
Copy link
Contributor

@bjorn3 I see! Thanks for the context. Is your plan to detect only those cases that don't affect codegen at all? This feels like a non-trivial change, but one that I would love to see. Complex enough though it's worth describing your strategy a bit up front. (I'd like to eventually extend it -- e.g., so that we can detect cases where the only thing that matters about a type is its size and collapse those instantiations, etc.)

@bjorn3
Copy link
Member Author

bjorn3 commented Feb 14, 2018

Is your plan to detect only those cases that don't affect codegen at all?

Yes, i am visiting the mir of a fn and storing all used TyParam's. During collection of trans items and translating calls all every subst which has no associated TyParam in their mir gets replaced by !.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't quite ready, but I did a quick read and accumulated a number of minor comments.

@@ -2762,3 +2762,51 @@ impl fmt::Display for SymbolName {
fmt::Display::fmt(&self.name, fmt)
}
}

pub fn ty_fn_sig<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe combine this with the existing fn_sig helper?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just moved it from librustc_trans/common.rs. It also uses fn_sig internally.

Copy link
Contributor

@nikomatsakis nikomatsakis Feb 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is that maybe we should make it part of fn_sig instead, so that you just write tcx.fn_sig(...) and not ty_fn_sig(tcx, ...).

use rustc::mir::{Mir, Rvalue, Promoted, Location};
use rustc::mir::visit::{Visitor, TyContext};

/// Replace substs which arent used by the function with TyError,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/arent/aren't/

use rustc::mir::visit::{Visitor, TyContext};

/// Replace substs which arent used by the function with TyError,
/// so that it doesnt end up in the binary multiple times
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/doesnt/doesn't/


/// Replace substs which arent used by the function with TyError,
/// so that it doesnt end up in the binary multiple times
pub(crate) fn collapse_interchangable_instances<'a, 'tcx>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you wrote a comment! But I think we could and should ultimately say more. I'd love to show a (small) example Rust program that would benefit, and then explain (in terms of that example) what this query inputs and outputs exactly.

e.g., some program like

fn foo<T>() { } // here, T is clearly unused =)

fn main() {
    foo::<u32>();
    foo::<u64>(); 
}

/// so that it doesnt end up in the binary multiple times
pub(crate) fn collapse_interchangable_instances<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut inst: Instance<'tcx>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we write "instance"? I find inst rather ambiguous ("instruction?")

}

let used_substs = used_substs_for_instance(tcx, inst);
inst.substs = tcx._intern_substs(&inst.substs.into_iter().enumerate().map(|(i, subst)| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems bad that this function's name is _intern_substs. Seems like you're not suposed to be calling it =)

}

#[derive(Debug, Default, Clone)]
pub struct UsedSubsts {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should call this UsedSubsts, but rather UsedParameters -- I think of substs as being the set of values that we use to substitute in. e.g., if you have struct Vec<T>, the T is not a subst but rather a generic parameter. In contrast, the u32 in Vec<u32> is a subst.

let used_substs = used_substs_for_instance(tcx, inst);
inst.substs = tcx._intern_substs(&inst.substs.into_iter().enumerate().map(|(i, subst)| {
if let Some(ty) = subst.as_type() {
let ty = if used_substs.substs.iter().find(|p|p.idx == i as u32).is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add some helper methods here to make this more readable?

e.g.,

if used_substs.param_is_used(p) {
    ty
} else {
    ...
}

let ty = if used_substs.substs.iter().find(|p|p.idx == i as u32).is_some() {
ty.into()
} else if let ty::TyParam(ref _param) = ty.sty {
//^ Dont replace <closure_kind> and other internal params
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't we bailing earlier for closures?

If not, it feels like the used_substs thing should just return a value that ensures that closure-kind and other parameters would be considered used, rather than special casing on this side.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldnt get that working :(

tcx.mk_ty(ty::TyNever)
}
} else {
// Can't use TyError as it gives some ICE in rustc_trans::callee::get_fn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, TyError is meant to be used when a compilation error has already been reported (that has not happened here). It's important we maintain that invariant or else legit errors may get suppressed.

@bjorn3
Copy link
Member Author

bjorn3 commented Feb 15, 2018

cc @eddyb

@eddyb
Copy link
Member

eddyb commented Feb 24, 2018

If we can't use TyErr, why not have the unsubstituted TyParam? I'd really like to avoid adding TyUnusedParam, and e.g. miri already supports evaluating with some unsubstituted parameters.

@bjorn3
Copy link
Member Author

bjorn3 commented Feb 24, 2018

What ParamTy idx should be used for the TyParam? I think there will be some code trying to replace that TyParam using the local Substs, which is will ICE when the index of the ParamTy is bigger than the length of the local Substs.

@bjorn3 bjorn3 force-pushed the deduplicate_instances branch 4 times, most recently from 7cb418c to 5b16548 Compare February 28, 2018 09:34
@nikomatsakis
Copy link
Contributor

@eddyb @bjorn3 -- do you want my review and feedback here? I'm not sure what is the status of this PR

@eddyb
Copy link
Member

eddyb commented Feb 28, 2018

@bjorn3 If you put the TyParam in the Substs (you can use Substs::identity_for_item to get the TyParams you need), nothing should substitute more than once.

So e.g. you start with Vec<T> and you have a [T] Substs, so the monomorphization substitution results in Vec<T>. That last type will not get substituted again (by correct code).

@bjorn3
Copy link
Member Author

bjorn3 commented Mar 1, 2018

@eddyb I get what you mean, but I think we need a custom type for params which are only dependent on size and align as @Manishearth wants anyway.

(I'd like to eventually extend it -- e.g., so that we can detect cases where the only thing that matters about a type is its size and collapse those instantiations, etc.)

@pietroalbini pietroalbini added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 5, 2018
@bors
Copy link
Contributor

bors commented Mar 5, 2018

☔ The latest upstream changes (presumably #48208) made this pull request unmergeable. Please resolve the merge conflicts.

@eddyb
Copy link
Member

eddyb commented Mar 6, 2018

@bjorn3 That's kind of hard, I wonder if @Manishearth meant "types which don't have a size that depends on type parameters" (e.g. Vec<T>), which is still doable with TyParam.

@bjorn3 bjorn3 force-pushed the deduplicate_instances branch from 5b16548 to 89eeacc Compare March 6, 2018 18:14
@Manishearth
Copy link
Member

I don't recall ever saying that -- got a link? I probably did, but I've completely forgotten the context 😄

@bjorn3
Copy link
Member Author

bjorn3 commented Mar 7, 2018

@Manishearth
Oops, I meant @nikomatsakis: #48139 (comment)

@bors
Copy link
Contributor

bors commented Mar 8, 2018

☔ The latest upstream changes (presumably #46882) made this pull request unmergeable. Please resolve the merge conflicts.

@bjorn3 bjorn3 force-pushed the deduplicate_instances branch from 89eeacc to f376ebc Compare March 9, 2018 09:30
@bors
Copy link
Contributor

bors commented Mar 13, 2018

☔ The latest upstream changes (presumably #48411) made this pull request unmergeable. Please resolve the merge conflicts.

@@ -819,7 +819,8 @@ for ty::TypeVariants<'gcx>
TyChar |
TyStr |
TyError |
TyNever => {
TyNever |
TyUnusedParam | ty::TyLayoutOnlyParam(_, _) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: formatting

@@ -482,7 +482,8 @@ fn ty_is_local_constructor(ty: Ty, in_crate: InCrate) -> bool {
ty::TyClosure(..) |
ty::TyGenerator(..) |
ty::TyGeneratorWitness(..) |
ty::TyAnon(..) => {
ty::TyAnon(..) |
ty::TyUnusedParam | ty::TyLayoutOnlyParam(_, _) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: formatting

@nikomatsakis
Copy link
Contributor

Still unsure of the status of this PR -- but I'm excited to see continued work on it! 💯

Just let me know when you want me to do something. =)

@bjorn3 bjorn3 force-pushed the deduplicate_instances branch from a9aef76 to 7a158b0 Compare March 30, 2018 09:06
@TimNN
Copy link
Contributor

TimNN commented Mar 30, 2018

Your PR failed on Travis. Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
Resolving deltas: 100% (613437/613437), completed with 4868 local objects.
---
[00:00:49] configure: rust.quiet-tests     := True
---
[00:45:28] .........................................................................i..........................
[00:45:36] ................i...................................................................................
---
[00:46:16] ............................................................................................i.......
[00:46:25] ................................................................i...................................
---
[00:47:29] .............................................i......................................................
---
[00:52:11] .............................i......................................................................
[00:52:28] ..............................................................i.....................................
[00:52:47] ...............................................i....................................................
[00:53:12] ....................................................................................................
[00:53:39] ....................................................................................................
[00:54:04] ....................................................................................................
[00:54:35] .i................................................................................................i.
[00:54:55] ..................................................test [run-pass] run-pass/mir_heavy_promoted.rs has been running for over 60 seconds
[00:55:17] ..................................................
[00:55:48] ....................................................................................................
[00:56:26] ...............................................................ii...................................
[00:57:09] ..........................i..............................................test [run-pass] run-pass/saturating-float-casts.rs has been running for over 60 seconds
[00:57:18] ......i.ii.................
[00:58:02] .......................................................................................iiiiiii......
---
[00:59:59] ....................................i...............................................................
[01:00:07] ....................................................................................................
[01:00:15] ..................i............................................................ii.iii...............
[01:00:22] ....................................................................................................
[01:00:30] ........i..............................i............................................................
[01:00:38] ....................................................................................................
[01:00:45] .....................i..............................................................................
[01:00:53] ....................................................................................................
[01:01:03] ....................................................................................................
[01:01:13] ....................................................................................................
[01:01:25] ....................................................................................................
[01:01:38] ....................................................................................................
[01:01:48] ..............i.....................................................................................
[01:01:58] .................i..ii..............................................................................
[01:02:07] ....................................................................................................
[01:02:18] ....................................................................................................
[01:02:27] ....................................................................................i...............
[01:02:38] ..............................i.....................................................................
---
[01:03:15] ...........................i........................................................................
[01:03:16] ....................................................................i...............................
[01:03:18] ................i.......................................................
---
[01:03:32] ...........i........................
---
[01:04:03] i....i.ii....i.............ii........iii......i..i...i...ii..i..i..ii.....
---
[01:04:06] thread 'main' panicked at 'Some tests failed', tools/compiletest/src/main.rs:478:22
[01:04:06] i.......i.....F................i......
[01:04:06] failures:
[01:04:06]
[01:04:06] ---- [codegen-units] codegen-units/item-collection/static-init.rs stdout ----
[01:04:06]
[01:04:06] These items should have been contained but were not:
[01:04:06]
[01:04:06] TRANS_ITEM fn static_init::foo[0]<!>
[01:04:06]
[01:04:06]
[01:04:06]
[01:04:06] These items were contained but should not have been:
[01:04:06]
[01:04:06] TRANS_ITEM fn static_init::foo[0]<i32> @@ static_init0[Internal]
[01:04:06]
[01:04:06]
[01:04:06] thread '[codegen-units] codegen-units/item-collection/static-init.rs' panicked at 'explicit panic', tools/compiletest/src/runtest.rs:2212:13
---
[01:04:06] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/codegen-units" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-units" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "codegen-units" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-3.9/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Zmiri -Zunstable-options " "--target-rustcflags" "-Crpath -O -Zmiri -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "3.9.1\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always"
[01:04:06] expected success, got: exit code: 101
[01:04:06]
[01:04:06]
[01:04:06] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:04:06] Build completed unsuccessfully in 0:19:39
[01:04:06] Makefile:58: recipe for target 'check' failed
[01:04:06] make: *** [check] Error 1
---
113480 ./obj/build/bootstrap/debug/incremental/bootstrap-qe1dy92fk757/s-ezn9fqzhzx-a4uf20-8h0vqcli171p
112704 ./obj/build/x86_64-unknown-linux-gnu/test/mir-opt
108032 ./obj/build/x86_64-unknown-linux-gnu/stage0/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends
102272 ./obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/incremental/core-1sv8kuz0m8z0z
102268 ./obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/incremental/core-1sv8kuz0m8z0z/s-eznajeugno-r28eu5-1057p3ydsmky8
---
$ cat obj/tmp/sccache.log
---
$ ls -lat $HOME/Library/Logs/DiagnosticReports/
ls: cannot access /home/travis/Library/Logs/DiagnosticReports/: No such file or directory
travis_time:end:10156b3c:start=1522404894059746033,finish=1522404894070668848,duration=10922815
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:1285b428
$ find $HOME/Library/Logs/DiagnosticReports -type f -name '*.crash' -not -name '*.stage2-*.crash' -not -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash' -exec printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" {} \; -exec head -750 {} \; -exec echo travis_fold":"end:crashlog \; || true
find: `/home/travis/Library/Logs/DiagnosticReports': No such file or directory
travis_time:end:1285b428:start=1522404894076052067,finish=1522404894082124816,duration=6072749
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:112b46d5
$ dmesg | grep -i kill
[   10.886528] init: failsafe main process (1093) killed by TERM signal

If this was not helpful or you have suggestes for improvements, please ping or otherwise contact @TimNN.

@oli-obk oli-obk added the WG-llvm Working group: LLVM backend code generation label Mar 30, 2018
@oli-obk
Copy link
Contributor

oli-obk commented Mar 30, 2018

cc @rust-lang/wg-codegen

@bors
Copy link
Contributor

bors commented Apr 7, 2018

☔ The latest upstream changes (presumably #49661) made this pull request unmergeable. Please resolve the merge conflicts.

@bjorn3 bjorn3 force-pushed the deduplicate_instances branch from 7a158b0 to bbe99cc Compare April 7, 2018 17:00
@TimNN
Copy link
Contributor

TimNN commented Apr 7, 2018

Your PR failed on Travis. Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
Receiving objects: 100% (161/161), 25.38 KiB | 25.38 MiB/s, done.
---
Resolving deltas: 100% (143/143), completed with 69 local objects.
---
[00:00:46] configure: rust.quiet-tests     := True
---
[00:04:37] tidy error: /checkout/src/librustc_trans/debuginfo/metadata.rs:1570: TODO is deprecated; use FIXME
[00:04:37] tidy error: /checkout/src/librustc_mir/monomorphize/deduplicate_instances.rs:69: line longer than 100 chars
[00:04:37] tidy error: /checkout/src/librustc_mir/monomorphize/deduplicate_instances.rs:74: line longer than 100 chars
[00:04:37] tidy error: /checkout/src/librustc_mir/monomorphize/deduplicate_instances.rs:76: line longer than 100 chars
[00:04:37] tidy error: /checkout/src/librustc/ty/mod.rs: missing trailing newline
[00:04:38] some tidy checks failed
[00:04:38]
[00:04:38]
[00:04:38] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
[00:04:38] expected success, got: exit code: 1
[00:04:38]
[00:04:38]
[00:04:38] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
[00:04:38] Build completed unsuccessfully in 0:01:46
[00:04:38] make: *** [tidy] Error 1
[00:04:38] Makefile:79: recipe for target 'tidy' failed
---
$ ls -lat $HOME/Library/Logs/DiagnosticReports/
ls: cannot access /home/travis/Library/Logs/DiagnosticReports/: No such file or directory
travis_time:end:066a3e80:start=1523120824857936064,finish=1523120824865114436,duration=7178372
travis_fold:end:after_failure.2
travis_fold:start:after_failure.3
travis_time:start:04689fa7
$ find $HOME/Library/Logs/DiagnosticReports -type f -name '*.crash' -not -name '*.stage2-*.crash' -not -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash' -exec printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" {} \; -exec head -750 {} \; -exec echo travis_fold":"end:crashlog \; || true
find: `/home/travis/Library/Logs/DiagnosticReports': No such file or directory
travis_time:end:04689fa7:start=1523120824871548739,finish=1523120824878148085,duration=6599346
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:01b48d56
$ dmesg | grep -i kill
[   10.800923] init: failsafe main process (1097) killed by TERM signal

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN.

@pietroalbini
Copy link
Member

Ping from triage @bjorn3! What's the status of this PR?

@bjorn3
Copy link
Member Author

bjorn3 commented Apr 16, 2018

Some tests are failing and it needs rebase.

@pietroalbini pietroalbini added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 23, 2018
@pietroalbini
Copy link
Member

Weekly ping from triage @bjorn3 :)

@bjorn3
Copy link
Member Author

bjorn3 commented Apr 23, 2018

Nothing changed and I havent got time yet.

@pietroalbini
Copy link
Member

Don't worry @bjorn3! I'm closing the PR to keep the queue tidy, but that doesn't mean the PR is rejected: when you get some free time please reopen it, and we will happily review it!

@pietroalbini pietroalbini added S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 23, 2018
@bjorn3
Copy link
Member Author

bjorn3 commented Apr 23, 2018

No problem

@bjorn3 bjorn3 deleted the deduplicate_instances branch July 23, 2020 10:53
@bjorn3 bjorn3 restored the deduplicate_instances branch July 27, 2023 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-llvm Working group: LLVM backend code generation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants