Skip to content

Use sess.opts.optimize instead of sess.opts.cg.opt_level for LTO optlevel #22530

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

Merged
merged 2 commits into from
Feb 25, 2015

Conversation

rprichard
Copy link
Contributor

Fixes #22525

I wasn't sure if I should reuse write::get_llvm_opt_level or not. It returns an llvm::CodeGenOptLevel, which is the Rust binding for CodeGenOpt::Level. lto.rs is passing an optlevel to LLVM's PassManagerBuilder, which takes an unsigned int. PassManagerBuilder's optlevel uses essentially the same enumeration (i.e. 0-3 with 2 as default), but it's implicit.

@rust-highfive
Copy link
Contributor

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see CONTRIBUTING.md for more information.

@dotdash
Copy link
Contributor

dotdash commented Feb 19, 2015

@bors r+ dc3bc90

Manishearth added a commit to Manishearth/rust that referenced this pull request Feb 19, 2015
 Fixes rust-lang#22525

I wasn't sure if I should reuse `write::get_llvm_opt_level` or not.  It returns an `llvm::CodeGenOptLevel`, which is the Rust binding for `CodeGenOpt::Level`. `lto.rs` is passing an optlevel to LLVM's `PassManagerBuilder`, which takes an unsigned int.  `PassManagerBuilder`'s optlevel uses essentially the same enumeration (i.e. 0-3 with 2 as default), but it's implicit.
@Manishearth
Copy link
Member

I have a suspicion this breaks the android build. See http://buildbot.rust-lang.org/builders/auto-linux-64-x-android-t/builds/3689

(Not yet confirmed if it really is due to this PR)

@rprichard
Copy link
Contributor Author

That seems plausible. The failing test run-pass/sepcomp-lib-lto.rs is built with -C lto -O, whose behavior changed with this PR. I wonder if the test would also fail with -C lto -C opt-level=2. If so, that would indicate this PR more strongly, but it'd also imply that LTO on Android was already broken, I think.

AFAICT, it seems that the Android NDK does not have pthread_atfork in any static or dynamic library for ARM. Maybe jemalloc is supposed to use the stub in src/rt/rust_android_dummy.c?

@Manishearth
Copy link
Member

I think @alexcrichton mentioned something about a bunch of missing symbols being hacked around on Android. I guess you should discuss with him?

Yeah, it seems like LTO on Android is partially broken. I guess we could land this and put up an issue for investigating this. Not sure.

@rprichard
Copy link
Contributor Author

I'm currently building Rust for Android so I can take a closer look at it.

@Manishearth
Copy link
Member

I'm able to build it at stage1 with no errors.

I'll need to try doing it for stage2, one moment.

(Moving the test from run-pass to compile-fail means that you don't need an android device to test it)

@Manishearth
Copy link
Member

Stage2 passes too. Hmm.

(I'm only testing compilation)

@rprichard
Copy link
Contributor Author

I'm able to reproduce the pthread_atfork build error on my machine now. I
built Rust with my patch. The test fails with either -C opt-level=2 -C
lto or with -O -C lto, but passes with -C opt-level=0 -C lto.

On Sat, Feb 21, 2015 at 2:16 PM, Manish Goregaokar <[email protected]

wrote:

Stage2 passes too. Hmm.


Reply to this email directly or view it on GitHub
#22530 (comment).

@Manishearth
Copy link
Member

Hm, I'd included your patch too, but I might have done it wrong.

Suggestions on how to proceed?

@rprichard
Copy link
Contributor Author

Here's the command-line I'm using to compile the test case:

RUSTC="/home/rprichard/work/rust-android-local/bin/rustc \
    --target=arm-linux-androideabi \
    -C linker=/home/rprichard/android-ndk-standalone-19/bin/arm-linux-androideabi-gcc"

$RUSTC ~/work/rust/src/test/auxiliary/sepcomp_lib.rs \
    -C codegen-units=3 --crate-type=rlib,dylib

$RUSTC ~/work/rust/src/test/run-pass/sepcomp-lib-lto.rs -C opt-level=2 -C lto -L.

It fails with this output:

error: linking with `/home/rprichard/android-ndk-standalone-19/bin/arm-linux-androideabi-gcc` failed: exit code: 1
note: "/home/rprichard/android-ndk-standalone-19/bin/arm-linux-androideabi-gcc" '"-Wl,--as-needed"' '"-Wl,--allow-multiple-definition"' '"-L"' '"/home/rprichard/work/rust-android-local/lib/rustlib/arm-linux-androideabi/lib"' '"-o"' '"sepcomp-lib-lto"' '"sepcomp-lib-lto.o"' '"-Wl,--whole-archive"' '"-lmorestack"' '"-Wl,--no-whole-archive"' '"-Wl,--gc-sections"' '"-Wl,-O1"' '"-nodefaultlibs"' '"/tmp/rustc.D4hSH49lQNTN/libstd-4e7c5e5c.rlib"' '"/tmp/rustc.D4hSH49lQNTN/liballoc-4e7c5e5c.rlib"' '"-L"' '"."' '"-L"' '"/home/rprichard/work/rust-android-local/lib/rustlib/arm-linux-androideabi/lib"' '"-L"' '"/home/rprichard/mess/android-test/.rust/lib/arm-linux-androideabi"' '"-L"' '"/home/rprichard/mess/android-test/lib/arm-linux-androideabi"' '"-Wl,--whole-archive"' '"-Wl,-Bstatic"' '"-Wl,--no-whole-archive"' '"-Wl,-Bdynamic"' '"-ldl"' '"-llog"' '"-lgcc"' '"-lc"' '"-lm"' '"-lcompiler-rt"'
note: /home/rprichard/android-ndk-standalone-19/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /tmp/rustc.D4hSH49lQNTN/liballoc-4e7c5e5c.rlib(r-jemalloc-jemalloc.pic.o): in function malloc_init_hard:jemalloc.c(.text.unlikely.malloc_init_hard+0x280): error: undefined reference to 'pthread_atfork'
collect2: ld returned 1 exit status

@Manishearth
Copy link
Member

@bors: r-

Getting this out of the queue until we solve the failure :)

@Manishearth
Copy link
Member

Ah, okay, I was trying to compile it a bit differently (by copying the invocation provided by compiletest and tweaking).

@rprichard
Copy link
Contributor Author

I think I've figured it out.

pthread_atfork comes from r-rust_builtin-rust_android_dummy.o, which is linked into libstd-4e7c5e5c.rlib. It's needed in r-jemalloc-jemalloc.pic.o in liballoc-4e7c5e5c.rlib. However, libstd comes before liballoc on the linker command-line. The linker examines libstd first, decides that r-rust_builtin-rust_android_dummy.o is unneeded and leaves it out. Then it examines liballoc and sees that pthread_atfork is missing. It doesn't revisit libstd.

With -C opt-level=0 -C lto, it happens to work because sepcomp-lib-lto.o pulls in other symbols from r-rust_builtin-rust_android_dummy.o. Namely, it pulls in __errno_location, log2, and log2f.

To help debug this issue, pass -C link-args="-Wl,-Map=output.map -Wl,--cref" -Z print-link-args -C save-temps to rustc.

-C opt-level=0 -C lto:

/home/rprichard/android-ndk-standalone-19/bin/arm-linux-androideabi-gcc
    -Wl,--as-needed
    -Wl,--allow-multiple-definition
    -L /home/rprichard/work/rust-android-local/lib/rustlib/arm-linux-androideabi/lib
    -o sepcomp-lib-lto
    sepcomp-lib-lto.o
    -Wl,--whole-archive -lmorestack -Wl,--no-whole-archive
    -Wl,--gc-sections
    -nodefaultlibs
    /tmp/rustc.2wZNcIqEwb2J/libstd-4e7c5e5c.rlib
    /tmp/rustc.2wZNcIqEwb2J/liballoc-4e7c5e5c.rlib
    -L .
    -L /home/rprichard/work/rust-android-local/lib/rustlib/arm-linux-androideabi/lib
    -L /home/rprichard/mess/android-test/.rust/lib/arm-linux-androideabi
    -L /home/rprichard/mess/android-test/lib/arm-linux-androideabi
    -Wl,--whole-archive
    -Wl,-Bstatic
    -Wl,--no-whole-archive
    -Wl,-Bdynamic
    -ldl
    -llog
    -lgcc
    -lc
    -lm
    -Wl,-Map=output.map
    -Wl,--cref
    -lcompiler-rt

cross-reference output:

# __errno_location                                  /tmp/rustc.X0fdWX76ezor/libstd-4e7c5e5c.rlib(r-rust_builtin-rust_android_dummy.o)
#                                                   sepcomp-lib-lto.o
# log2                                              /tmp/rustc.X0fdWX76ezor/libstd-4e7c5e5c.rlib(r-rust_builtin-rust_android_dummy.o)
#                                                   sepcomp-lib-lto.o
#                                                   /home/rprichard/android-ndk-standalone-19/bin/../sysroot/usr/lib/libm.so
# log2f                                             /tmp/rustc.X0fdWX76ezor/libstd-4e7c5e5c.rlib(r-rust_builtin-rust_android_dummy.o)
#                                                   sepcomp-lib-lto.o
#                                                   /home/rprichard/android-ndk-standalone-19/bin/../sysroot/usr/lib/libm.so
# pthread_atfork                                    /tmp/rustc.X0fdWX76ezor/libstd-4e7c5e5c.rlib(r-rust_builtin-rust_android_dummy.o)
#                                                   /tmp/rustc.X0fdWX76ezor/liballoc-4e7c5e5c.rlib(r-jemalloc-jemalloc.pic.o)

@rprichard
Copy link
Contributor Author

I think the fix is to move rust_android_dummy.o out of libstd into its own library, then either:

  • Move it later in the linker command-line, or maybe,
  • Wrap it with -Wl,--whole-archive -Wl,--no-whole-archive (like we do with -lmorestack).

@rprichard
Copy link
Contributor Author

The Android LTO problem was already reported as #18800. We need to break out pthread_atfork from librust_builtin. Prior to finding that issue, I split it out into a "rust_android_alloc_dummy" library, which works, but it's ugly.

Can we merge this PR without first fixing the Android LTO problem? This PR isn't really breaking Android LTO, it's just making the existing brokenness more obvious.

@Manishearth
Copy link
Member

That sounds good to me, though I'd want @dotdash or @alexcrichton to confirm if that's what we want to do.

@@ -167,7 +167,12 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);

let opt = sess.opts.cg.opt_level.unwrap_or(0) as libc::c_uint;
let opt = match sess.opts.optimize {
config::No => 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like -Clto without optimizations doesn't even perform dead code elimination, which makes LTO rather pointless, IMO.
Can we please make -Clto imply -Copt-level=2? (unless specified explicitly, of course)

Copy link
Member

Choose a reason for hiding this comment

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

While perhaps not super useful, it does allow varying axes of configuration as well as perhaps a smoke test of some form. I would be ok, however, to have -Clto switch the default optimization level as ell though.

@alexcrichton
Copy link
Member

Can we merge this PR without first fixing the Android LTO problem?

Unfortunately this PR cannot land until all tests are passing, we won't merge in-progress patches which have known failing tests.

@Manishearth
Copy link
Member

@alexcrichton Apparently the Android LTO problem is basically that LTO is broken on Android -- this PR just uncovers another place where it's broken. I wouldn't call it an in-progress patch, it's more of a patch that disturbs a test in a broken area.

@alexcrichton
Copy link
Member

That's not really the point at hand though. This test is currently running on android and passing. With this PR it looks like the test starts failing. We can't merge until that's dealt with one way or another.

@Manishearth
Copy link
Member

Alright.

@pnkfelix
Copy link
Member

The old school way to address link errors like this was to list the offending input multiple times on the linker invocation. Can we do that here, get libstd added a second time to to the end?

@rprichard
Copy link
Contributor Author

That's not really the point at hand though. This test is currently running on android and passing. With this PR it looks like the test starts failing. We can't merge until that's dealt with one way or another.

That makes sense. I suppose I was wondering if there were some way to disable the test for Android, because we already know that the Android-LTO combination is currently broken.

@rprichard
Copy link
Contributor Author

FWIW, here's my fix for the Android-LTO issue. rprichard@9511c06. It just splits out pthread_atfork from librust_builtin.a. I verified that it fixed the sepcomp-lib-lto.rs failure.

@rprichard
Copy link
Contributor Author

It looks like it's possible to disable a test using a comment:

// ignore-android

@alexcrichton
Copy link
Member

Yes adding // ignore-android is fine.

@Manishearth
Copy link
Member

Yeah, that's sort of what I meant when I said that we can merge this PR without having the test pass. Sorry if I wasn't clear :)

@dotdash
Copy link
Contributor

dotdash commented Feb 24, 2015

@bors r+ 9167c62

@bors
Copy link
Collaborator

bors commented Feb 24, 2015

⌛ Testing commit 9167c62 with merge 308b79f...

@bors
Copy link
Collaborator

bors commented Feb 24, 2015

💔 Test failed - auto-linux-32-nopt-t

@Manishearth
Copy link
Member

(Not a real failure, I'm trying to get eddy's UFCS patch to land first so I canceled the build. Sorry.)

@Manishearth
Copy link
Member

@bors: retry

@Manishearth
Copy link
Member

@bors: force

@Manishearth
Copy link
Member

@bors: retry

@Manishearth
Copy link
Member

@bors retry clean force

@bors
Copy link
Collaborator

bors commented Feb 24, 2015

⌛ Testing commit 9167c62 with merge ad04cce...

bors added a commit that referenced this pull request Feb 24, 2015
Fixes #22525

I wasn't sure if I should reuse `write::get_llvm_opt_level` or not.  It returns an `llvm::CodeGenOptLevel`, which is the Rust binding for `CodeGenOpt::Level`. `lto.rs` is passing an optlevel to LLVM's `PassManagerBuilder`, which takes an unsigned int.  `PassManagerBuilder`'s optlevel uses essentially the same enumeration (i.e. 0-3 with 2 as default), but it's implicit.
@alexcrichton
Copy link
Member

Tests all passed but didn't get picked up by homu, merging manually.

@alexcrichton alexcrichton merged commit 9167c62 into rust-lang:master Feb 25, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

-C lto -O does not enable LLVM optimizations for the LTO passes
8 participants