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

[MIR] Add Storage{Live,Dead} statements to emit llvm.lifetime.{start,end}. #35409

Merged
merged 2 commits into from
Aug 14, 2016

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Aug 6, 2016

Storage live ranges are tracked for all MIR variables and temporaries with a drop scope.
StorageLive is lowered to llvm.lifetime.start and StorageDead to llvm.lifetime.end.

There are some improvements possible here, such as:

  • pack multiple storage liveness statements by using the index of first local + u64 bitset
  • enforce that locals are not directly accessed outside their storage live range
  • shrink storage live ranges for never-borrowed locals to initialization -> last use
  • emit storage liveness statements for all temporaries
    • however, the remaining ones are always SSA immediates, so they'd be noop in MIR trans
    • could have a flag on the temporary that its storage is irrelevant (a la C's old register)
      • would also deny borrows if necessary
      • this seems like an overcompliation and with packing & optimizations it may be pointless

Even in the current state, it helps stage2 rustc compile boiler without overflowing (see #35408).

A later addition fixes #26764 and closes #27372 by emitting .section directives for dylib metadata to avoid them being allocated into memory or read as .note. For this PR, those bugs were tripping valgrind.

@rust-highfive
Copy link
Collaborator

r? @nikomatsakis

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

if temp_lifetime.is_some() {
this.cfg.push(block, Statement {
source_info: source_info,
kind: StatementKind::StorageLive(temp.clone())
Copy link
Member

Choose a reason for hiding this comment

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

Make a helper function in cfg, since you’re constructing this multiple times manually.

This should become this.cfg.push_storage_live(source_info, temp);

@arielb1
Copy link
Contributor

arielb1 commented Aug 6, 2016

Test please

Assign(Lvalue<'tcx>, Rvalue<'tcx>),

/// Start a live range for the storage of the local.
StorageLive(Lvalue<'tcx>),
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, should this be restricted to base lvalues or something like that? Meh, I guess it's ok to use Lvalue<'tcx> here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Local would be great, but even then, it would not be applicable to ReturnPointer or args.

@nikomatsakis
Copy link
Contributor

Test please

Seems like a good use for @scottcarr's MIR testing framework.

}
}
bcx
}
Copy link
Contributor

@scottcarr scottcarr Aug 8, 2016

Choose a reason for hiding this comment

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

Is there some way to refactor the arms? The only difference is End.call or Start.call, right?

EDIT: (I edited my original note which said "why not call lvalue_trans?" -- which we do not need)

Copy link
Member Author

Choose a reason for hiding this comment

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

We need to do nothing if the local is not an Lvalue.
Using a method taking lvalue and the base::Lifetime would work, yeah.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Aug 9, 2016

OK so @eddyb convinced me that most of my concerns were moot. r=me modulo the following:

@eddyb
Copy link
Member Author

eddyb commented Aug 10, 2016

@bors r=nikomatsakis p=1 (if this gets into the nightly, it may fix a couple crates)

@bors
Copy link
Contributor

bors commented Aug 10, 2016

📌 Commit 7def9f5 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Aug 10, 2016

⌛ Testing commit 7def9f5 with merge a5973b6...

@bors
Copy link
Contributor

bors commented Aug 11, 2016

💔 Test failed - auto-linux-64-opt

@nikomatsakis
Copy link
Contributor

Failures are valgrind failures:

---- [run-pass-valgrind] run-pass-valgrind/coerce-match-calls.rs stdout ----

error: test run failed!
status: exit code: 100
command: /usr/bin/valgrind --error-exitcode=100 --fair-sched=try --quiet --soname-synonyms=somalloc=NONE --suppressions=/buildslave/rust-buildbot/slave/auto-linux-64-opt/build/src/etc/x86.supp --tool=memcheck --leak-check=full x86_64-unknown-linux-gnu/test/run-pass-valgrind/coerce-match-calls.stage2-x86_64-unknown-linux-gnu
stdout:
------------------------------------------

------------------------------------------
stderr:
------------------------------------------
==20600== Syscall param read(buf) points to unaddressable byte(s)
==20600==    at 0x401B177: read (syscall-template.S:84)
==20600==    by 0x40059FF: open_verify.constprop.7 (dl-load.c:1949)
==20600==    by 0x4005CD9: open_path (dl-load.c:2066)
==20600==    by 0x4008BE0: _dl_map_object (dl-load.c:2307)
==20600==    by 0x400D9D1: openaux (dl-deps.c:63)
==20600==    by 0x4010393: _dl_catch_error (dl-error.c:187)
==20600==    by 0x400E011: _dl_map_object_deps (dl-deps.c:254)
==20600==    by 0x40034F9: dl_main (rtld.c:1610)
==20600==    by 0x4019461: _dl_sysdep_start (dl-sysdep.c:249)
==20600==    by 0x4004E79: _dl_start_final (rtld.c:307)
==20600==    by 0x4004E79: _dl_start (rtld.c:413)
==20600==    by 0x4000CC7: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==20600==  Address 0xffee10a00 is on thread 1's stack
==20600==  in frame #1, created by open_verify.constprop.7 (dl-load.c:1695)
==20600== 

------------------------------------------

Could be real!

@eddyb
Copy link
Member Author

eddyb commented Aug 11, 2016

@nikomatsakis I pinged @alexcrichton but I don't think he had time to look over them yet.
AFAICT, those are in rtld, which could only be a problem at the end of execution, if we've ruined any rtld state - but the stack trace makes me believe it's actually at the start of execution.

@eddyb
Copy link
Member Author

eddyb commented Aug 11, 2016

@bors retry (hoping this is spurious)

@eddyb
Copy link
Member Author

eddyb commented Aug 11, 2016

@bors p=0

@bors
Copy link
Contributor

bors commented Aug 13, 2016

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

@eddyb
Copy link
Member Author

eddyb commented Aug 14, 2016

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Aug 14, 2016

📌 Commit 02aec40 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Aug 14, 2016

⌛ Testing commit 02aec40 with merge 4d03edd...

@bors
Copy link
Contributor

bors commented Aug 14, 2016

💔 Test failed - auto-linux-64-opt

@eddyb
Copy link
Member Author

eddyb commented Aug 14, 2016

I can't reproduce don't have valgrind locally at all 😕.

@eddyb
Copy link
Member Author

eddyb commented Aug 14, 2016

Argh #26764 strikes again, this time libstd's .note.rustc section being too large for just one rtld function to alloca at once, according to valgrind.

@eddyb
Copy link
Member Author

eddyb commented Aug 14, 2016

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Aug 14, 2016

📌 Commit 1bb1444 has been approved by nikomatsakis

@eddyb
Copy link
Member Author

eddyb commented Aug 14, 2016

@bors p=2

@bors
Copy link
Contributor

bors commented Aug 14, 2016

⌛ Testing commit 1bb1444 with merge 1d5b758...

bors added a commit that referenced this pull request Aug 14, 2016
[MIR] Add Storage{Live,Dead} statements to emit llvm.lifetime.{start,end}.

Storage live ranges are tracked for all MIR variables and temporaries with a drop scope.
`StorageLive` is lowered to `llvm.lifetime.start` and `StorageDead` to `llvm.lifetime.end`.

There are some improvements possible here, such as:
* pack multiple storage liveness statements by using the index of first local + `u64` bitset
* enforce that locals are not directly accessed outside their storage live range
* shrink storage live ranges for never-borrowed locals to initialization -> last use
* emit storage liveness statements for *all* temporaries
 * however, the remaining ones are *always* SSA immediates, so they'd be noop in MIR trans
 * could have a flag on the temporary that its storage is irrelevant (a la C's old `register`)
   * would also deny borrows if necessary
    * this seems like an overcompliation and with packing & optimizations it may be pointless

Even in the current state, it helps stage2 `rustc` compile `boiler` without overflowing (see #35408).

A later addition fixes #26764 and closes #27372 by emitting `.section` directives for dylib metadata to avoid them being allocated into memory or read as `.note`. For this PR, those bugs were tripping valgrind.
@bors bors merged commit 1bb1444 into rust-lang:master Aug 14, 2016
@eddyb eddyb deleted the mir-storage-stmts branch August 14, 2016 22:28
@cuviper
Copy link
Member

cuviper commented Aug 14, 2016

I don't know about the rest, but thanks for the incidental .note cleanup! 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
9 participants