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

LLVM assertion with -C lto -g -O on static lib #23566

Closed
japaric opened this issue Mar 20, 2015 · 5 comments
Closed

LLVM assertion with -C lto -g -O on static lib #23566

japaric opened this issue Mar 20, 2015 · 5 comments
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️

Comments

@japaric
Copy link
Member

japaric commented Mar 20, 2015

STR

#![crate_type = "staticlib"]
#![feature(core)]
#![feature(lang_items)]
#![feature(no_std)]
#![no_std]

extern crate core;

mod lang_items {
    use core::fmt::Arguments;

    #[lang = "stack_exhausted"]
    extern "C" fn stack_exhausted() { }

    #[lang = "eh_personality"]
    extern "C" fn eh_personality() { }

    #[lang = "panic_fmt"]
    fn panic_fmt(_: &Arguments, _: &(&'static str, usize)) -> !  {
        loop  {}
    }
}

pub enum Input {
    Floating,
}

pub mod low {
    use super::Mode;

    pub enum Pin {
        _0,
    }

    pub struct Cr(u32);

    impl Cr {
        pub fn set(&mut self, pin: Pin, mode: Mode) {
            self.0 |= mode.value() << (4 * pin as u8)
        }
    }
}

pub mod high {
    use super::Mode;

    pub enum Pin {
        _8,
    }

    pub struct Cr(u32);

    impl Cr {
        pub fn set(&mut self, pin: Pin, mode: Mode) {
            self.0 |= mode.value() << (4 * pin as u8)
        }
    }
}

pub enum Mode { Input(Input) }

impl Mode {
    fn value(&self) -> u32 {
        match *self {
            Mode::Input(Input::Floating) => 4,
        }
    }
}

Output

rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/lib/CodeGen/LexicalScopes.cpp:179: llvm::LexicalScope* llvm::LexicalScopes::getOrCreateRegularScope(llvm::MDNode*): Assertion `DISubprogram(Scope).describes(MF->getFunction())' failed.

cc @michaelwoerister Same error message as #17677, but I don't know if it's the same bug, this one needs -O.

@jdm jdm added A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ labels Mar 20, 2015
@rprichard
Copy link
Contributor

I reduced the test case to:

#![crate_type = "staticlib"]
pub fn set1(x: &mut u32) { *x = 123 }
pub fn set2(x: &mut u32) { *x = 123 }

The compiler options are the same (-C lto -g -O). The interesting thing is that the bodies of set1 and set2 must be identical. Perhaps there's an LLVM optimization that's merging the two, and that's breaking debug information?

@japaric
Copy link
Member Author

japaric commented Mar 20, 2015

@rprichard Thanks for the reduced test case!

The interesting thing is that the bodies of set1 and set2 must be identical.

Yeah, I was under the impression that this may be the cause.

Perhaps there's an LLVM optimization that's merging the two, and that's breaking debug information?

Could be, I'm not familiar with LLVM to confirm this. @dotdash ^^^ do you know if LLVM has an optimization pass that does that?

@michaelwoerister
Copy link
Member

Thanks for the report. This looks sufficiently different from #17677 to warrant it's own issue. I haven't look into it closely but I think the root cause for this error is not the same as for #17677 (where I don't think it is related to two functions having the same body).

@dotdash
Copy link
Contributor

dotdash commented Apr 6, 2015

Perhaps there's an LLVM optimization that's merging the two, and that's breaking debug information?

Could be, I'm not familiar with LLVM to confirm this. @dotdash ^^^ do you know if LLVM has an optimization pass that does that?

Yes, the mergefunc pass does that. The problem here seems to be that mergefunc turns set2 into a jump to set1, but then LTO inlines set1 into set2 again, producing bad debug metadata.

After optimizations:

define void @_ZN4set120h703cb75c1e01d663eaaE(i32* noalias nocapture dereferenceable(4)) unnamed_addr #0 {
entry-block:
  tail call void @llvm.dbg.value(metadata i32* %0, i64 0, metadata !14, metadata !20), !dbg !21
  store i32 123, i32* %0, align 4, !dbg !22
  ret void, !dbg !21
}

define void @_ZN4set220h34cbfe792e780cc1paaE(i32* noalias nocapture dereferenceable(4)) unnamed_addr #0 {
  tail call void @_ZN4set120h703cb75c1e01d663eaaE(i32* %0)
  ret void
}

After LTO:

define void @_ZN4set120h703cb75c1e01d663eaaE(i32* noalias nocapture dereferenceable(4)) unnamed_addr #0 {
entry-block:
  tail call void @llvm.dbg.value(metadata i32* %0, i64 0, metadata !14, metadata !20), !dbg !21
  store i32 123, i32* %0, align 4, !dbg !22
  ret void, !dbg !21
}

define void @_ZN4set220h34cbfe792e780cc1paaE(i32* noalias nocapture dereferenceable(4)) unnamed_addr #0 {
  tail call void @llvm.dbg.value(metadata i32* %0, i64 0, metadata !14, metadata !20), !dbg !21
  store i32 123, i32* %0, align 4, !dbg !22, !alias.scope !24
  ret void
}

Relevant metadata:

!4 = !{!"0x2e\00set1\00set1\00_ZN10issue235664set1E\002\000\001\000\000\00256\001\002", !5, !6, !7, null, void (i32*)* @_ZN4set120h703cb75c1e01d663eaaE, !2, null, !13} ; [ DW_TAG_subprogram ] [line 2] [def] [set1]
!21 = !MDLocation(line: 2, scope: !4)

So both functions claim to have the scope of set1, and that triggers the assertion.

Changing set2 to:

pub fn2(x: &mut u32) { set1(x) }

Triggers the inlining even without mergefunc, and we get:

define void @_Z4set2Pi(i32* nocapture %x) #0 {
  tail call void @llvm.dbg.value(metadata i32* %x, i64 0, metadata !14, metadata !18), !dbg !26
  tail call void @llvm.dbg.value(metadata i32* %x, i64 0, metadata !27, metadata !18), !dbg !29
  store i32 123, i32* %x, align 4, !dbg !30, !tbaa !21
  ret void, !dbg !31
}

I suppose the re-declaration of %x is just ignored and thus the error doesn't happen.

For now, I suppose that it would be sensible to disable mergefunc when compiling with debug information.

@alexcrichton
Copy link
Member

This no longer causes an assert on nightly, so closing as fixed. Yay!

nox added a commit to nox/rust that referenced this issue May 12, 2018
The crash that happened in rust-lang#23566 doesn't happen anymore with the LLVM mergefunc
pass enabled and it hugely reduces code size (for example it shaves off 10% of the
final Servo executable). This patch reenables it.
bors added a commit that referenced this issue May 13, 2018
Reenable the MergeFunctions pass

The crash that happened in #23566 doesn't happen anymore with the LLVM mergefunc
pass enabled and it hugely reduces code size (for example it shaves off 10% of the
final Servo executable). This patch reenables it.

For those wondering, [here are the docs from LLVM about this pass](http://llvm.org/docs/MergeFunctions.html).
nox added a commit to nox/rust that referenced this issue May 15, 2018
The crash that happened in rust-lang#23566 doesn't happen anymore with the LLVM mergefunc
pass enabled and it hugely reduces code size (for example it shaves off 10% of the
final Servo executable). This patch reenables it.
bors added a commit that referenced this issue May 16, 2018
Reenable the MergeFunctions pass

The crash that happened in #23566 doesn't happen anymore with the LLVM mergefunc
pass enabled and it hugely reduces code size (for example it shaves off 10% of the
final Servo executable). This patch reenables it.

For those wondering, [here are the docs from LLVM about this pass](http://llvm.org/docs/MergeFunctions.html).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
Projects
None yet
Development

No branches or pull requests

6 participants