Since a few days ago, I'm unable to bootstrap rustc on ARM. Stage0 passes ok, but then during libcore compilation I'm getting a consistent crash:
(gdb) run
Starting program: ../arm-unknown-linux-gnueabihf/stage1/bin/rustc --cfg stage1 -C codegen-units=1 -C target-cpu=cortex-a5 -C target-feature=-neon,-slowfpvmlx -Z orbit -C link-args=-s -O --cfg rtopt -C rpath -C prefer-dynamic --target=arm-unknown-linux-gnueabihf -C target-feature=+v7,+vfp3 -L arm-unknown-linux-gnueabihf/rt -L native=../arm-unknown-linux-gnueabihf/llvm/Release/lib --out-dir arm-unknown-linux-gnueabihf/stage1/lib/rustlib/arm-unknown-linux-gnueabihf/lib -C extra-filename=-fe3cdf61 -C metadata=fe3cdf61 src/libcore/lib.rs
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
[New Thread 0xb23c8280 (LWP 10171)]
Program received signal SIGILL, Illegal instruction.
[Switching to Thread 0xb23c8280 (LWP 10171)]
0xb5ccd4c8 in rustc_trans::mir::constant::MirConstContext::new::hfbf8e74461aa3c9a ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
(gdb) bt
#0 0xb5ccd4c8 in rustc_trans::mir::constant::MirConstContext::new::hfbf8e74461aa3c9a ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#1 0xb5cca2bc in rustc_trans::mir::constant::_$LT$impl$u20$mir..MirContext$LT$$u27$bcx$C$$u20$$u27$tcx$GT$$GT$::trans_constant::h0fc06663a5c5fd5c () from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#2 0xb5cc97e8 in rustc_trans::mir::operand::_$LT$impl$u20$mir..MirContext$LT$$u27$bcx$C$$u20$$u27$tcx$GT$$GT$::trans_operand::hf76be65ffae28ad3 () from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#3 0xb5cda61c in rustc_trans::mir::rvalue::_$LT$impl$u20$mir..MirContext$LT$$u27$bcx$C$$u20$$u27$tcx$GT$$GT$::trans_rvalue_operand::hd939e0a331e9c597 () from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#4 0xb5cbff28 in rustc_trans::mir::block::_$LT$impl$u20$mir..MirContext$LT$$u27$bcx$C$$u20$$u27$tcx$GT$$GT$::trans_block::hb1d87007c9e87f30 () from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#5 0xb5ba9aa8 in rustc_trans::mir::trans_mir::hf51ccc32c7a8ddd3 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#6 0xb5ba1ff0 in rustc_trans::base::trans_closure::hcb1c30ddf81aba40 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#7 0xb5bab570 in rustc_trans::base::trans_fn::h1508ebeec7351f87 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#8 0xb5bb8950 in rustc_trans::base::trans_item::hd6a260625a685bf2 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#9 0xb5bd3e10 in _$LT$base..TransItemsWithinModVisitor$LT$$u27$a$C$$u20$$u27$tcx$GT$$u20$as$u20$rustc..hir..intravisit..Visitor$LT$$u27$v$GT$$GT$::visit_item::heb661116fa8a1e87 () from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#10 0xb5bd2524 in rustc::hir::intravisit::walk_item::hf7ed747a4fa46491 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#11 0xb5bcbbe4 in _$LT$base..TransModVisitor$LT$$u27$a$C$$u20$$u27$tcx$GT$$u20$as$u20$rustc..hir..intravisit..Visitor$LT$$u27$v$GT$$GT$::visit_item::h65d871e71b3668c9 () from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#12 0xb5bbf8ec in rustc_trans::base::trans_crate::hca67d2711539a441 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_trans-fe3cdf61.so
#13 0xb6e06194 in rustc_driver::driver::phase_4_translate_to_llvm::h5f028163cc963293 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_driver-fe3cdf61.so
#14 0xb6e04640 in rustc_driver::driver::compile_input::_$u7b$$u7b$closure$u7d$$u7d$::h540343a1efd859c9 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_driver-fe3cdf61.so
#15 0xb6e10f78 in rustc_driver::driver::phase_3_run_analysis_passes::_$u7b$$u7b$closure$u7d$$u7d$::h0c96940e550f2879 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_driver-fe3cdf61.so
#16 0xb6e16264 in rustc::ty::context::TyCtxt::create_and_enter::h167e75cbc44e6d50 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_driver-fe3cdf61.so
#17 0xb6e0a56c in rustc_driver::driver::phase_3_run_analysis_passes::h75db68819aee0b65 ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_driver-fe3cdf61.so
#18 0xb6dd47b8 in rustc_driver::driver::compile_input::h5e5e4501615d7d4b ()
from ../arm-unknown-linux-gnueabihf/stage1/lib/librustc_driver-fe3cdf61.so
Backtrace stopped: Cannot access memory at address 0x1d1cfff8
(gdb) disass 0xb5ccd4c8,+1
Dump of assembler code from 0xb5ccd4c8 to 0xb5ccd4c9:
=> 0xb5ccd4c8 <_ZN11rustc_trans3mir8constant15MirConstContext3new17hfbf8e74461aa3c9aE+404>: str r0, [r0, r8]!
Before getting that trace I had no idea it was related to MIR in any way. I'll have to give old trans a shot.
EDIT:
Yeah, old trans chugs along without a hitch.
@eddyb Looks like an LLVM codegen issue that's triggered by MIR - any debugging suggestions?
@alexcrichton Provided it's not just my llvm, do ARM issues have any bearing on switching to MIR by default?
@petevine I don't understand, is the instruction being executed not supported on the architecture you're running it on? Because then it's a coincidence that the librustc_trans/mir/constant.rs is compiled with that instruction and you could probably reproduce with code using types of the same size and shape.
The instruction is just a standard register store (word size) with preindexed offset, so it's probably about wrong offset or alignment.
About three days ago it was still crashing (a full rebuild of llvm didn't help either) but today, it's back to normal.
No, I was a little too hasty. It was just my little experiment (done stage0 with old trans) which allowed stage1 to proceed even with -Z orbit but the same scenario has just happened during stage2 libcore.
So this bug could be summarised like this:
rustc built with-Zorbitcrashes when trying to use-Zorbitbut not old trans codegen
@eddyb I've got a debug trace:
Program received signal SIGILL, Illegal instruction.
[Switching to Thread 0xb2a282b0 (LWP 25309)]
collections::vec::{{impl}}::extend_desugared<core::option::Option<rustc_trans::mir::constant::Const>,core::iter::Map<core::ops::Range<usize>, closure>> (self=<optimized out>, iterator=...)
at src/libcollections/vec.rs:1424
1424 ptr::write(self.get_unchecked_mut(len), element);
(gdb) bt
#0 collections::vec::{{impl}}::extend_desugared<core::option::Option<rustc_trans::mir::constant::Const>,core::iter::Map<core::ops::Range<usize>, closure>> (self=<optimized out>, iterator=...) at src/libcollections/vec.rs:1424
#1 collections::vec::{{impl}}::from_iter<core::option::Option<rustc_trans::mir::constant::Const>,core::iter::Map<core::ops::Range<usize>, closure>> (iter=...) at src/libcollections/vec.rs:1325
#2 rustc_data_structures::indexed_vec::{{impl}}::from_iter<rustc::mir::repr::Local,core::option::Option<rustc_trans::mir::constant::Const>,core::iter::Map<core::ops::Range<usize>, closure>> (iter=...) at src/librustc_data_structures/indexed_vec.rs:180
#3 core::iter::iterator::Iterator::collect<core::iter::Map<core::ops::Range<usize>, closure>,rustc_data_structures::indexed_vec::IndexVec<rustc::mir::repr::Local, core::option::Option<rustc_trans::mir::constant::Const>>> (self=...) at src/libcore/iter/iterator.rs:1207
#4 rustc_trans::mir::constant::{{impl}}::new (ccx=<optimized out>, mir=<optimized out>, substs=<optimized out>, args=...)
at src/librustc_trans/mir/constant.rs:221
#5 0xb6554cd4 in rustc_trans::mir::constant::{{impl}}::trans_constant (self=0xb2a15170, bcx=<optimized out>, constant=<optimized out>)
at src/librustc_trans/mir/constant.rs:911
#6 0xb65541e0 in rustc_trans::mir::operand::{{impl}}::trans_operand (self=0x0, bcx=0xb2a13b60, operand=<optimized out>)
at src/librustc_trans/mir/operand.rs:234
#7 0xb65644cc in rustc_trans::mir::rvalue::{{impl}}::trans_rvalue_operand (self=<optimized out>, bcx=..., rvalue=<optimized out>,
debug_loc=...) at src/librustc_trans/mir/rvalue.rs:476
#8 0xb654aa28 in rustc_trans::mir::statement::{{impl}}::trans_statement (statement=<optimized out>, self=<optimized out>, bcx=...)
at src/librustc_trans/mir/statement.rs:36
#9 rustc_trans::mir::block::{{impl}}::trans_block (self=<optimized out>, bb=...) at src/librustc_trans/mir/block.rs:103
#10 0xb64354e8 in rustc_trans::mir::trans_mir (fcx=<optimized out>) at src/librustc_trans/mir/mod.rs:249
#11 0xb642df4c in rustc_trans::base::trans_closure (ccx=<optimized out>, decl=<optimized out>, body=<optimized out>,
llfndecl=<optimized out>, instance=..., inlined_id=271, sig=<optimized out>, abi=<optimized out>, closure_env=...)
at src/librustc_trans/base.rs:1854
#12 0xb6456f78 in rustc_trans::base::trans_instance (ccx=<optimized out>, instance=...) at src/librustc_trans/base.rs:1953
#13 rustc_trans::trans_item::{{impl}}::define (self=<optimized out>, ccx=<optimized out>) at src/librustc_trans/trans_item.rs:89
#14 0xb6446660 in rustc_trans::base::trans_crate (tcx=..., mir_map=<optimized out>, analysis=...) at src/librustc_trans/base.rs:2638
#15 0xb6e0bc74 in rustc_driver::driver::phase_4_translate_to_llvm::{{closure}} () at src/librustc_driver/driver.rs:1055
#16 rustc::util::common::time<rustc_trans::CrateTranslation,closure> (what=..., f=..., do_it=<optimized out>)
at src/librustc/util/common.rs:38
#17 rustc_driver::driver::phase_4_translate_to_llvm (tcx=..., mir_map=..., analysis=...) at src/librustc_driver/driver.rs:1053
#18 0xb6e0a1a4 in rustc_driver::driver::compile_input::{{closure}} (tcx=..., mir_map=..., analysis=..., result=...)
at src/librustc_driver/driver.rs:204
#19 0xb6e167f4 in rustc_driver::driver::phase_3_run_analysis_passes::{{closure}}<closure,core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>> (tcx=...) at src/librustc_driver/driver.rs:1016
#20 0xb6e1b8a4 in std::thread::local::{{impl}}::with<core::cell::Cell<core::option::Option<(*const rustc::ty::context::tls::ThreadLocalGlobalCtxt, *const rustc::ty::context::tls::ThreadLocalInterners)>>,closure,core::result::Result<core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>, usize>> (f=..., self=<optimized out>) at src/libstd/thread/local.rs:245
#21 rustc::ty::context::tls::enter<closure,core::result::Result<core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>, usize>> (gcx=<optimized out>, interners=<optimized out>, f=...) at src/librustc/ty/context.rs:903
#22 std::thread::local::{{impl}}::with<core::cell::Cell<fn(syntax_pos::Span, &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error>>,closure,core::result::Result<core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>, usize>> (f=..., self=<optimized out>) at src/libstd/thread/local.rs:245
#23 rustc::ty::context::tls::enter_global<closure,core::result::Result<core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>, usize>> (gcx=..., f=...) at src/librustc/ty/context.rs:887
#24 rustc::ty::context::{{impl}}::create_and_enter<closure,core::result::Result<core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>, usize>> (s=<optimized out>, arenas=<optimized out>, def_map=..., named_region_map=...,
map=..., freevars=..., maybe_unused_trait_imports=..., region_maps=..., lang_items=..., stability=..., crate_name=..., f=...)
at src/librustc/ty/context.rs:685
#25 0xb6e0ff50 in rustc_driver::driver::phase_3_run_analysis_passes<closure,core::result::Result<(rustc::session::config::OutputFilenames, rustc_trans::CrateTranslation), usize>> (sess=<optimized out>, hir_map=..., analysis=..., resolutions=..., arenas=<optimized out>,
name=..., f=...) at src/librustc_driver/driver.rs:898
#26 0xb6dd55e0 in rustc_driver::driver::compile_input (sess=<optimized out>, cstore=<optimized out>, cfg=..., input=0xb2a25ff8,
outdir=0xb2a26028, output=0xb2a26018, addl_plugins=..., control=0xb2a257e8) at src/librustc_driver/driver.rs:170
#27 0xb6dbf10c in rustc_driver::run_compiler_with_file_loader<syntax::codemap::RealFileLoader> (args=..., callbacks=...,
loader=<optimized out>) at src/librustc_driver/lib.rs:220
#28 rustc_driver::run_compiler (args=..., callbacks=...) at src/librustc_driver/lib.rs:157
#29 0xb6dcce68 in rustc_driver::run::{{closure}} () at src/librustc_driver/lib.rs:135
#30 rustc_driver::monitor::{{closure}}<closure> () at src/librustc_driver/lib.rs:1043
#31 std::panic::{{impl}}::call_once<(),closure> (self=...) at src/libstd/panic.rs:251
#32 std::panicking::try::call<closure> (f=0xb2a27c54) at src/libstd/panicking.rs:272
#33 0xb6b32238 in panic_unwind::__rust_maybe_catch_panic (f=0x40000000, data=0xaa482e18 "", data_ptr=0xb2a27c50, vtable_ptr=0xb2a27c4c)
at src/libpanic_unwind/lib.rs:91
#34 0xb6dcd8a8 in std::thread::local::{{impl}}::with<core::cell::Cell<usize>,closure,core::result::Result<(), Box<Any>>> (
self=<optimized out>, f=...) at src/libstd/thread/local.rs:245
#33 0xb6b32238 in panic_unwind::__rust_maybe_catch_panic (f=0x40000000, data=0xaa482e18 "", data_ptr=0xb2a27c50, vtable_ptr=0xb2a27c4c)
at src/libpanic_unwind/lib.rs:91
#34 0xb6dcd8a8 in std::thread::local::{{impl}}::with<core::cell::Cell<usize>,closure,core::result::Result<(), Box<Any>>> (
self=<optimized out>, f=...) at src/libstd/thread/local.rs:245
#35 std::panicking::try<(),std::panic::AssertUnwindSafe<closure>> (f=...) at src/libstd/panicking.rs:235
#36 std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,()> (f=...) at src/libstd/panic.rs:307
#37 alloc::boxed::{{impl}}::call_box<(),closure> (self=0x7f56eb88, args=<optimized out>) at src/liballoc/boxed.rs:544
#38 0xb6b218e8 in alloc::boxed::{{impl}}::call_once<(),()> (self=...) at src/liballoc/boxed.rs:554
#39 std::sys_common::thread::start_thread (main=<optimized out>) at src/libstd/sys/common/thread.rs:23
#40 std::sys::thread::{{impl}}::new::thread_start (main=0x7f56ec48) at src/libstd/sys/unix/thread.rs:74
#41 0xb2cd5fa0 in start_thread (arg=0xb2a282b0) at pthread_create.c:314
#42 0xb69a8d9c in ?? () at ../ports/sysdeps/unix/sysv/linux/arm/nptl/../clone.S:92 from /lib/arm-linux-gnueabihf/libc.so.6
Remember the get<usize> jemalloc segfault? There's no jemalloc here and MIR bootstrap used to work fine about 3 weeks ago.
Looks like this is indeed a coincidence, you should be able to reproduce using types with the same layout.
This snippet should generate the same instructions and trigger SIGILL:
#[inline(never)]
fn foo(n: usize) -> Vec<Option<(*mut (), &'static ())>> {
(0..n).map(|_| None).collect()
}
fn main() {
let _ = (foo(10), foo(32));
}
Yes it does! I initially forgot to use optimizations and the code ran fine. As expected, it also runs fine without -Zorbit or at opt-level=1.
Here's the difference in the generated assembly:
21c21
< 25b8: ba000070 blt 2780 <_ZN6sigill3foo17hfaa1209845a9b530E+0x214>
---
> 25b8: ba00006f blt 277c <_ZN6sigill3foo17hfaa1209845a9b530E+0x210>
26c26
< 25cc: eb003fc5 bl 124e8 <__rust_allocate>
---
> 25cc: eb003fbf bl 124d0 <__rust_allocate>
29c29
< 25d8: 0a00006d beq 2794 <_ZN6sigill3foo17hfaa1209845a9b530E+0x228>
---
> 25d8: 0a00006b beq 278c <_ZN6sigill3foo17hfaa1209845a9b530E+0x220>
49c49
< 2628: 23000000 movwcs r0, #0
---
> 2628: 23000000 movwcs r0, #0
67c67
< 2670: eb003fae bl 12530 <__rust_reallocate>
---
> 2670: eb003fa8 bl 12518 <__rust_reallocate>
71c71
< 2680: eb003f98 bl 124e8 <__rust_allocate>
---
> 2680: eb003f92 bl 124d0 <__rust_allocate>
79c79
< 26a0: e7a00008 str r0, [r0, r8]!
---
> 26a0: e7a01008 str r1, [r0, r8]!
If anything, this looks like a LLVM bug. cc @alexcrichton
I was about to ask if opening a bug upstream with both llvm-ir and assembly versions side by side was a good course of action?
@petevine Our LLVM has been getting put of date because upgrading it was blocked by moving to only cmake.
But now that's done and we're waiting for the upgrade to happen, AFAIK.
I've already seen a few bugs that already had fixes upstream, some of which got cherry-picked.
I pinged @alexcrichton to see what he knows about the upgrade and about testing if it helps with this issue, since finding completely new bugs in LLVM can be hit and miss.
Here's an LLVM upgrade FYI: https://github.com/rust-lang/rust/pull/34743
Thanks guys. The stage is set for a quick test in the future.
@eddyb Oops, the oldest "new" rustc I've got here is dated July 16th and it doesn't produce the minimal example crash. The one that does (Jun 12th) was built before LLVM cmake transition and rt away from cmake (but it's still the same LLVM revision) so maybe the bootstrap is fixed too.
@petevine If you confirm the bootstrap is fixed, we can close this.
No change; clearly I must have run out of MIR bootstrapped rustc's :) The latter part of https://github.com/rust-lang/rust/issues/34427#issuecomment-230890468 still holds.
@eddyb Updating LLVM to 3.9 made no difference. Clutching at straws here - I gave a rough estimate when the regression'd started and now wonder if the choice of stage0 compiler (I might have switched around that time) could have any impact beyond stage0?
@petevine The stage0 compiler is the one relevant here, it's the one compiling the librustc_trans that goes into stage1/bin/rustc, and which contains the problematic instruction.
Yeah, that's what I meant by beyond stage0 - did my experiment of turning MIR off for stage0, and then turning it back on for stage1, getting the same crash during stage2's libcore, conclusively prove the issue couldn't propagate from the snapshot used?
@petevine Alright, so it's not fixed yet. And my snippet from https://github.com/rust-lang/rust/issues/34427#issuecomment-231554262 stopped triggering it?
Because that's pretty much identical to the code in rustc_trans.
I'm sure your snippet would trigger the crash, it's just I don't have any recent rustc's bootstrapped with MIR. The last one I've got is dated Jun 10th and it produces crashing code which means the issue was already present back then.
So how was I still able to do a MIR bootstrap? Would that suggest the choice of stage0 compiler somehow propagates after all?
@petevine You only need to be able to compile that snippet for ARM, with -Zorbit -O and run it.
I don't really know what to say if 3.9 doesn't help with that. Unless clang can reproduce the problem.
I'm not sure what you mean by being able to do a MIR bootstrap.
I meant an --enable-orbit bootstrap. OK, I'll try repeating the experiment with LLVM 3.9 and -Zorbit taking over in stage1 - if it still crashes during stage2, the question of LLVM will be settled.
@petevine In a way, the snippet is more important than rustc_trans, because it's simpler and can be reduced further. However, I don't have access to an ARM machine to run the code and thus reduce it.
Sure, but let me repeat, old trans bootstrapped rustc doesn't produce crashing code (while still using -Zorbit -O) which sounds very strange to me :)
edit:
Also, a SIGILL on Linux can be triggered by failed allocations or OOM conditions - can we eliminate this angle?
Ah, I understood otherwise. That's confusing, given that stage0 wasn't bootstrapped with MIR trans, and yet it produced crashing rustc_trans code.
It's entirely possible the stage0 compiler I'm currently using was bootstrapped with MIR trans. It's not the official beta, if that's what you meant.
Ay, it must have been - it's my own nightly build rustc 1.11.0-nightly (0554abac6)
I was hoping to reproduce in clang: https://godbolt.org/g/8BnjtE - however, it produces:
str r0, [r0, r1]
add r0, r0, r1
IIUC, str r0, [r0, r1]!, if valid, would be equivalent to these two instructions.
EDIT: And if I try to emit it via asm I get "error: source register and base register can't be identical".
Yeah, that immediately struck me as wrong but I thought, maybe the compiler is that smart!
@petevine Can you get good / bad versions of the LLVM IR for my snippet? Looking at the assembly again, I don't see how storing r0 could possibly work - it's supposed to store r1 which is 0.
Sure, I think I should have both versions lying around somewhere.
sigill.zip
FWIW, this is more or less what's happening in the good ASM: https://godbolt.org/g/mU6Egb.
@petevine Hmm, one crucial element is undef - that is, if you replace None by unsafe { std::mem::zeroed() }, it should work even with -Zorbit -O.
Correct!
Reproduction! https://godbolt.org/g/YHu7H8
Impressive! Shall I direct you to a preexisting LLVM issue? ;)
@petevine Well, I just filed https://llvm.org/bugs/show_bug.cgi?id=28809.
Great job, thx! I'm just going to link to my previous feeble attempt from there.
All I could get from an ARM engineer is that a check like this one is missing from ARMLoadStoreOptimizer but he has no clue as to where in the file, and I'm honestly a bit lost, but I'll keep looking.
EDIT: Oh, and it was introduced between LLVM 3.7 and 3.8, but I don't have the setup for further bisection.
Odd, looks like registers are assigined in a way that results in invalid instructions:
# *** IR Dump Before Virtual Register Rewriter ***:
# Machine code for function _Z3fooPcS_i: Post SSA
Function Live Ins: %R0 in %vreg7, %R1 in %vreg8, %R2 in %vreg9
0B BB#0: derived from LLVM BB %0
Live Ins: %R0 %R1 %R2
16B %vreg9<def> = COPY %R2; GPRnopc:%vreg9
32B %vreg8<def> = COPY %R1; GPR:%vreg8
48B %vreg15<def> = COPY %R0; GPR:%vreg15
64B CMPrr %vreg15, %vreg8, pred:14, pred:%noreg, %CPSR<imp-def>; GPR:%vreg15,%vreg8
80B Bcc <BB#1>, pred:1, pred:%CPSR<kill>
Successors according to CFG: BB#4(0x30000000 / 0x80000000 = 37.50%) BB#1(0x50000000 / 0x80000000 = 62.50%)
96B BB#4:
Predecessors according to CFG: BB#0
128B B <BB#3>
Successors according to CFG: BB#3(?%)
144B BB#1:
Predecessors according to CFG: BB#0
160B %vreg4<def> = MOVi 0, pred:14, pred:%noreg, opt:%noreg; GPR:%vreg4
Successors according to CFG: BB#2(?%)
192B BB#2: derived from LLVM BB %.lr.ph
Predecessors according to CFG: BB#2 BB#1
240B %vreg15<earlyclobber,def,tied2> = STR_PRE_REG %vreg13<undef>, %vreg15<tied0>, %vreg9, 0, pred:14, pred:%noreg; GPR:%vreg15,%vreg13 GPRnopc:%vreg9
256B STRi12 %vreg4, %vreg15, 4, pred:14, pred:%noreg; mem:ST4[%sunkaddr8+4](tbaa=!4) GPR:%vreg4,%vreg15
272B CMPrr %vreg8, %vreg15, pred:14, pred:%noreg, %CPSR<imp-def>; GPR:%vreg8,%vreg15
320B Bcc <BB#2>, pred:1, pred:%CPSR<kill>
336B B <BB#3>
Successors according to CFG: BB#3(0x04000000 / 0x80000000 = 3.12%) BB#2(0x7c000000 / 0x80000000 = 96.88%)
352B BB#3: derived from LLVM BB %._crit_edge
Predecessors according to CFG: BB#2 BB#4
384B %R0<def> = COPY %vreg15; GPR:%vreg15
400B BX_RET pred:14, pred:%noreg, %R0<imp-use>
# End machine code for function _Z3fooPcS_i.
# *** IR Dump After Virtual Register Rewriter ***:
# Machine code for function _Z3fooPcS_i: Post SSA
Function Live Ins: %R0, %R1, %R2
0B BB#0: derived from LLVM BB %0
Live Ins: %R0 %R1 %R2
64B CMPrr %R0, %R1, pred:14, pred:%noreg, %CPSR<imp-def>
80B Bcc <BB#1>, pred:1, pred:%CPSR<kill>
Successors according to CFG: BB#4(0x30000000 / 0x80000000 = 37.50%) BB#1(0x50000000 / 0x80000000 = 62.50%)
96B BB#4:
Live Ins: %R0
Predecessors according to CFG: BB#0
128B B <BB#3>
Successors according to CFG: BB#3(?%)
144B BB#1:
Live Ins: %R0 %R1 %R2
Predecessors according to CFG: BB#0
160B %R3<def> = MOVi 0, pred:14, pred:%noreg, opt:%noreg
Successors according to CFG: BB#2(?%)
192B BB#2: derived from LLVM BB %.lr.ph
Live Ins: %R0 %R1 %R2 %R3
Predecessors according to CFG: BB#2 BB#1
240B %R0<earlyclobber,def,tied2> = STR_PRE_REG %R0<undef>, %R0<kill,tied0>, %R2, 0, pred:14, pred:%noreg
256B STRi12 %R3, %R0, 4, pred:14, pred:%noreg; mem:ST4[%sunkaddr8+4](tbaa=!4)
272B CMPrr %R1, %R0, pred:14, pred:%noreg, %CPSR<imp-def>
320B Bcc <BB#2>, pred:1, pred:%CPSR<kill>
336B B <BB#3>
Successors according to CFG: BB#3(0x04000000 / 0x80000000 = 3.12%) BB#2(0x7c000000 / 0x80000000 = 96.88%)
352B BB#3: derived from LLVM BB %._crit_edge
Live Ins: %R0
Predecessors according to CFG: BB#2 BB#4
400B BX_RET pred:14, pred:%noreg, %R0<imp-use>
# End machine code for function _Z3fooPcS_i.
From IRC, looks like the undef is disabling earlyclobber's ability to prevent source == base:
01:57 <TNorthover> That earlyclobber should take care of it.
01:57 <zq> it doesn't
01:57 <zq> the problem is that %vreg13<undef> is computed to have zero live interval
01:57 <zq> so ra thinks: no liveness, no clobber, no problem
@eddyb -- is the current status that this is an LLVM bug? Is there a known fix?
triage: P-high
This seems like a fairly bad regression, at least on ARM. I'm not sure what action we ought to take to address it though!
Assigning to eddyb since he's been keeping on top of this. Nice job.
@nikomatsakis The bug is https://llvm.org/bugs/show_bug.cgi?id=28809 and some choices were presented in IRC but they're invasive changes to multiple LLVM targets, i.e. something LLVM developers familiar with those targets would have to investigate and work on.
I can try to push for this or get someone to tell me what steps I can take for at least a partial fix, if need be.
@eddyb do we have any idea if there is some way to workaround the problem on our side?
How does our behavior map to the C code in that bug report (which seems to read an uninitialized variable)?
@nikomatsakis We end up with it from Option<(*mut T, &U)>, which is (undef, null) for None.
And then working with that in a loop (e.g. a Vec of that Option) ends up in the bad codegen.
This is a coincidence of factors that would be hard to work around meaningfully, short of translating enums with the nullable ptr optimization applied as memcpy with 0 instead of setting only one field.
@eddyb
short of translating enums with the nullable ptr optimization applied as memcpy with 0 instead of setting only one field.
I was going to suggest exactly something like this, at least on ARM.
Fixed!
Why did you close this? It should be obvious as long as the bootstrap compiler remains unchanged the crash should happen right there at stage0.
Trying to defer the crash to stage1 by passing -Zorbit=off reveals it's completely broken now:
Reading symbols from armv7-unknown-linux-gnueabihf/stage1/bin/rustc...(no debugging symbols found)...done.
Program received signal SIGSEGV, Segmentation fault.
#0 __GI___libc_free (mem=0x1d1d1d1d) at malloc.c:2929
#1 0xb6df7c30 in ?? () from ../armv7-unknown-linux-gnueabihf/stage1/lib/libstd-836a4172.so
@brson Mind updating the bootstrap beta to a slightly newer one with all the backports? Although the next beta release would use the next stable which will be the current (fixed) beta.
Two years later, do we still need the workaround?
https://github.com/rust-lang/rust/blob/780658a464603fa755d94b27f72a375bd81d07ea/src/librustc_codegen_ssa/mir/place.rs#L306-L314
Most helpful comment
@petevine Well, I just filed https://llvm.org/bugs/show_bug.cgi?id=28809.