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 error and build failure: "piece covers entire variable" #35547

Closed
bfops opened this issue Aug 9, 2016 · 16 comments
Closed

LLVM error and build failure: "piece covers entire variable" #35547

bfops opened this issue Aug 9, 2016 · 16 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) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@bfops
Copy link
Contributor

bfops commented Aug 9, 2016

This aggressive build failure happens consistently if you try to build rust-clippy with opt-level=1 set. Here's a fork that does it out of the box: https://github.com/bfops/rust-clippy.git.

piece covers entire variable
  tail call void @llvm.dbg.value(metadata %"17.rustc::hir::Expr"** %1, i64 0, metadata !70093, metadata !8774), !dbg !70097
!70093 = !DILocalVariable(arg: 3, scope: !70077, file: !41572, line: 1948, type: !9419)
!8774 = !DIExpression(DW_OP_bit_piece, 0, 64)
piece is larger than or outside of variable
  tail call void @llvm.dbg.value(metadata %"17.rustc::hir::Expr"** %2, i64 0, metadata !70093, metadata !8776), !dbg !70097
!70093 = !DILocalVariable(arg: 3, scope: !70077, file: !41572, line: 1948, type: !9419)
!8776 = !DIExpression(DW_OP_bit_piece, 64, 64)
LLVM ERROR: Broken function found, compilation aborted!
error: Could not compile `clippy_lints`.
@sanxiyn sanxiyn added the A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) label Aug 11, 2016
@thepowersgang
Copy link
Contributor

I've recently encountered this when compiling a program from my OS project (just one out of several userland binaries)

(Compiling https://github.com/thepowersgang/rust_os/blob/master/Usermode/fileviewer/src/main.rs using rustc 1.13.0-nightly (923bac459 2016-09-06))

piece is larger than or outside of variable
  tail call void @llvm.dbg.value(metadata void (i8*)** %3, i64 0, metadata !5538, metadata !5557), !dbg !5554
!5538 = !DILocalVariable(arg: 3, scope: !5539, file: !293, line: 1, type: !2033)
!5557 = !DIExpression(DW_OP_bit_piece, 128, 64)
piece is larger than or outside of variable
  tail call void @llvm.dbg.value(metadata void (i8*)** %3, i64 0, metadata !5538, metadata !5557), !dbg !5567
!5538 = !DILocalVariable(arg: 3, scope: !5539, file: !293, line: 1, type: !2033)
!5557 = !DIExpression(DW_OP_bit_piece, 128, 64)
LLVM ERROR: Broken function found, compilation aborted!

Notably - The function call mentioned does not appear in the file created by --emit llvm-ir

@thepowersgang
Copy link
Contributor

Occurs up with optimisation levels 1, 2, and s but not 0 or 3.

With level 1, only a single call is mentioned, and different optimisation levels change the ! numbers

@thepowersgang
Copy link
Contributor

@bfops - Your branch has bit-rotted against nightly.

@arielb1 arielb1 added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ labels Sep 8, 2016
@bfops
Copy link
Contributor Author

bfops commented Sep 8, 2016

Thanks, fixed! Error still happens for me on the updated branch.

@thepowersgang
Copy link
Contributor

thepowersgang commented Sep 10, 2016

I've located the last working nightly - rustc 1.12.0-nightly (a005b6785 2016-08-02) (dated 2016-08-03) compiles both my code and @bfops' fork (bfops/rust-clippy@e63c81c) successfully, but rustc 1.12.0-nightly (0a3180baa 2016-08-03) (dated 2016-08-04) fails to compile both.

Changes between these two revisions: a005b67...0a3180b

@thepowersgang
Copy link
Contributor

From some (very slow) commit bisecting - it looks like ee977e7 is at fault - but I do not know how (and I'm not 100% sure it is that commit)

@thepowersgang
Copy link
Contributor

cc @eddyb - The above commit was by you - can you see a reason for it to cause this error?

@eddyb
Copy link
Member

eddyb commented Sep 13, 2016

This looks lika a LLVM bug, we don't emit DW_OP_bit_piece ourselves, so LLVM may be optimizing a newtype out of memory into a value but shoot itself in the foot by using DW_OP_bit_piece.

@thepowersgang
Copy link
Contributor

https://llvm.org/bugs/show_bug.cgi?id=23712 - A similar issue on LLVM's tracker - Caused by bad debug information (incorrect size information for a variable)
https://llvm.org/bugs/show_bug.cgi?id=24923 - Also same error message, this time caused by the same root cause (bad size information) but due to two types with the same name.

@thepowersgang
Copy link
Contributor

thepowersgang commented Oct 9, 2016

Thanks to bugpoint - it looks like the culprit function in my case is

_ZN298_$LT$wtk..input..button..BoxCb$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..ops..Fn$LT$$LP$$RF$$u27$b1$u20$wtk..input..button..Button$LT$T$C$$u20$wtk..input..button..BoxCb$LT$$u27$a$C$$u20$T$GT$$GT$$C$$u20$$RF$$u27$b2$u20$mut$u20$wtk..window..WindowTrait$LT$$u27$b3$GT$$u20$$u2b$$u20$$u27$b2$RP$$GT$$GT$4call17hc4b025e85098d2b2E

Aka <BoxCb<'a, T> as Fn(&Button<T, BoxCb<T>>, &WindowTrait)>::call - which is a manual implementation of Fn for a container (Source)

  call void @llvm.dbg.declare(metadata { %"11.wtk::Button<wtk::Colour, wtk::input::button::BoxCb<wtk::Colour>>.35.317.599.13"*, { i8*, void (i8*)** } }* %arg1, metadata !424, metadata !425), !dbg !426
!424 = !DILocalVariable(arg: 2, scope: !377, file: !378, line: 26, type: !391)
!425 = !DIExpression(DW_OP_deref, DW_OP_plus, 0)

Is converted into

  call void @llvm.dbg.value(metadata %"11.wtk::Button<wtk::Colour, wtk::input::button::BoxCb<wtk::Colour>>.35.317.599.13"* %1, i64 0, metadata !17, metadata !22), !dbg !23
!17 = !DILocalVariable(arg: 2, scope: !4, file: !5, line: 26, type: !18)
!22 = !DIExpression(DW_OP_bit_piece, 0, 64)

I can't see anything directly here that fits the two bugs I mentioned above, but I'm not proficient in LLVM IR.

@thepowersgang
Copy link
Contributor

thepowersgang commented Oct 9, 2016

Strike that last note:

%arg1 = alloca { %"11.wtk::Button<wtk::Colour, wtk::input::button::BoxCb<wtk::Colour>>.35.317.599.13"*, { i8*, void (i8*)** } }
...
!391 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&wtk::input::button::Button<wtk::surface::Colour, wtk::input::button::BoxCb<wtk::surface::Colour>>", baseType: !392, size: 64, align: 64)

The alloca is for two pointers (128 bits), but the debug information associated with the variable is 64 bits long

(Reduced IR thanks to bugpoint at https://gist.github.com/thepowersgang/e9dce3f87dee14575576d08f602bf396 , only difference to broken areas is the debug info numbers)

@michaelwoerister
Copy link
Member

@thepowersgang Nice find!

@michaelwoerister
Copy link
Member

So here is a smaller case that produces that "incorrect" IR. I'm putting "incorrect" into quotes because it's not completely wrong. The alloca is of a different type than the what the debuginfo says, but that is because the debuginfo only describes a part of the alloca.

#![feature(unboxed_closures)]
#![feature(fn_traits)]
#![crate_type="rlib"]

pub trait Trait {}
pub struct Button;
pub struct Callback;

#[inline(never)]
fn other<'a, 'b>(args: (&'a Button, &'b mut Trait)) {
    let _ = args;
}

impl<'a, 'b> ::std::ops::FnOnce<(&'a Button, &'b mut Trait)> for Callback
{
    type Output = ();

    extern "rust-call" fn call_once(self, args: (&'a Button, &'b mut Trait)) {
        // self.0.call(args)
        other(args)
    }
}

This generates the following IR (filtered for interesting parts):

; Function Attrs: uwtable
define void @"_ZN155_$LT$lib..Callback$u20$as$u20$core..ops..FnOnce$LT$$LP$$RF$$u27$a$u20$lib..Button$C$$u20$$RF$$u27$b$u20$mut$u20$lib..Trait$u20$$u2b$$u20$$u27$b$RP$$GT$$GT$9call_once17h8c75272c3c1fa0f7E"(%Button* noalias readonly, i8* nonnull, void (i8*)** nonnull) unnamed_addr #1 !dbg !24 {
entry-block:
  %arg1 = alloca { %Button*, { i8*, void (i8*)** } }
  %args = alloca { %Button*, { i8*, void (i8*)** } }
  call void @llvm.dbg.declare(metadata { %Button*, { i8*, void (i8*)** } }* %arg1, metadata !31, metadata !32), !dbg !30
  ; ...

  call void @llvm.dbg.declare(metadata { %Button*, { i8*, void (i8*)** } }* %arg1, metadata !33, metadata !34), !dbg !30
  call void @llvm.dbg.declare(metadata { %Button*, { i8*, void (i8*)** } }* %args, metadata !38, metadata !18), !dbg !37
  ; ...
}

!10 = !DICompositeType(tag: DW_TAG_structure_type, name: "(&lib::Button, &mut Trait)", file: !7, size: 192, align: 64, elements: !11, identifier: "{tuple {&{struct lib/45447b7afbd5e544f7d0f1df0fccd26014d9850130abd3f020b89ff96b82079f/5}}{&mut{trait lib/45447b7afbd5e544f7d0f1df0fccd26014d9850130abd3f020b89ff96b82079f/4}}}")
!13 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&lib::Button", baseType: !14, size: 64, align: 64)
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "&mut Trait", scope: !6, file: !7, size: 128, align: 64, elements: !2, identifier: "{&mut{trait lib/45447b7afbd5e544f7d0f1df0fccd26014d9850130abd3f020b89ff96b82079f/4}}")
!31 = !DILocalVariable(arg: 2, scope: !24, file: !5, line: 1, type: !13)
!32 = !DIExpression(DW_OP_deref, DW_OP_plus, 0)
!33 = !DILocalVariable(arg: 3, scope: !24, file: !5, line: 1, type: !16)
!34 = !DIExpression(DW_OP_deref, DW_OP_plus, 8)
!38 = !DILocalVariable(name: "args", scope: !36, file: !5, line: 19, type: !10)

There are a couple of problematic things about this IR:

  • Why is there separate debuginfo for args and also for the components of args? That seems wrong.
  • We should probably use DW_OP_bit_piece instead of !DIExpression(DW_OP_deref, DW_OP_plus, 8) when describing components of a value. This is something from a time before DW_OP_bit_piece was a thing in LLVM.

@cuviper
Copy link
Member

cuviper commented Oct 13, 2016

Like #36774, this reduced test also appears to fail in older rustc with MIR enabled. I guess that makes sense, since the error is similar and you bisected the same commit to blame.

I'm testing with official rustc builds now, not with distro LLVM that we thought was to blame, and also setting RUSTC_BOOTSTRAP_KEY since the test uses features. 1.13.0-beta.1 and 1.12.0 fail this test, but 1.12.0 is fine with -Zorbit=off. 1.11.0 and 1.10.0 are normally fine, but fail when adding -Zorbit. 1.9.0 actually succeeds either way (maybe MIR was too young?) and 1.8.0 is pre-MIR.

bors added a commit that referenced this issue Oct 16, 2016
debuginfo: Handle spread_arg case in MIR-trans in a more stable way.

Use `VariableAccess::DirectVariable` instead of `VariableAccess::IndirectVariable` in order not to make LLVM's SROA angry. This is a step towards fixing #36774 and #35547. At least, I can build Cargo with optimizations + debuginfo again.

r? @eddyb
bors added a commit that referenced this issue Oct 17, 2016
debuginfo: Handle spread_arg case in MIR-trans in a more stable way.

Use `VariableAccess::DirectVariable` instead of `VariableAccess::IndirectVariable` in order not to make LLVM's SROA angry. This is a step towards fixing #36774 and #35547. At least, I can build Cargo with optimizations + debuginfo again.

r? @eddyb
@thepowersgang
Copy link
Contributor

The above fix has fixed my issue. @bfops Does it fix the issue you were encountering?

@bfops
Copy link
Contributor Author

bfops commented Oct 24, 2016

My repro is fixed on the latest nightly! I'm happy to close if nobody else has outstanding concerns.

@bfops bfops closed this as completed Oct 26, 2016
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) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants