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

Incremental compilation regression from 1.79 to 1.80: rustc-LLVM ERROR: Intervals are contiguous/overlapping #128555

Closed
seritools opened this issue Aug 2, 2024 · 14 comments · Fixed by #128677
Assignees
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ llvm-fixed-upstream Issue expected to be fixed by the next major LLVM upgrade, or backported fixes T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@seritools
Copy link
Contributor

seritools commented Aug 2, 2024

Code

Repro repository and steps: #128555 (comment)

I've bisected between 1.79.0 and 1.80.0:

searched nightlies: from nightly-2024-04-28 to nightly-2024-06-07
regressed nightly: nightly-2024-05-10
searched commit range: 87293c9...8f9080d
regressed commit: cb93c24

bisected with cargo-bisect-rustc v0.6.9

Host triple: x86_64-pc-windows-msvc
Reproduce with:

cargo bisect-rustc --start 1.79.0 --end 1.80.0 --preserve -- build --release -p <crate-name>
Old context

Context

It's a company project with a workspace that compiles ~680 crates on a clean compile.

From initial testing it seems like an incremental compilation bug :S cargo build works, cargo build --release fails, but when setting incremental = false in [profile.relese], cargo build --release succeeds again.

cargo build --release -p <crate-name> also reproduces the issue, dropping the number of crates down to "only" 203.

This is our profile config:

[profile.dev]
debug = 0
incremental = true
opt-level = 1

[profile.dev.package."*"]
opt-level = 3

[profile.dev.build-override]
codegen-units = 8
debug = 0
debug-assertions = false
opt-level = 2
overflow-checks = false

[profile.release]
debug = 1
# overwritten in xtask for production builds
incremental = true

[profile.release.build-override]
codegen-units = 8
debug = 0
debug-assertions = false
opt-level = 0
overflow-checks = false

Meta

This reproduces on 1.80 and the current nightly (as of writing this ticket). This does not reproduce on 1.79.0.

rustc --version --verbose:

rustc 1.80.0 (051478957 2024-07-21)
binary: rustc
commit-hash: 051478957371ee0084a7c0913941d2a8c4757bb9
commit-date: 2024-07-21
host: x86_64-pc-windows-msvc
release: 1.80.0
LLVM version: 18.1.7

and

rustc 1.82.0-nightly (8e86c9567 2024-08-01)
binary: rustc
commit-hash: 8e86c9567154dc5a9ada15ab196d23eae2bd7d89
commit-date: 2024-08-01
host: x86_64-pc-windows-msvc
release: 1.82.0-nightly
LLVM version: 19.1.0

Error output

Intervals are contiguous
!40 = !{i8 -20, i8 -17, i8 4, i8 -20}
rustc-LLVM ERROR: Broken module found, compilation aborted!
error: could not compile `<crate name>` (lib)

There is no backtrace being printed, even with RUST_BACKTRACE=1.

@seritools seritools added C-bug Category: This is a bug. 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. labels Aug 2, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 2, 2024
@seritools
Copy link
Contributor Author

It's a proprietary code base, but I'll try my best to minimize the dependencies and code and see if I can get to something shareable. If you've got any other ideas on what to test or try, please let me know!

@scottmcm
Copy link
Member

scottmcm commented Aug 3, 2024

That LLVM metadata in the error looks like the kind that would be used with !range, but it's particularly surprising to me because as far as I know rustc only ever emits range metadata with a single range in it:

fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {
if self.sess().target.arch == "amdgpu" {
// amdgpu/LLVM does something weird and thinks an i64 value is
// split into a v2i32, halving the bitwidth LLVM expects,
// tripping an assertion. So, for now, just disable this
// optimization.
return;
}
if self.cx.sess().opts.optimize == OptLevel::No {
// Don't emit metadata we're not going to use
return;
}
unsafe {
let llty = self.cx.val_ty(load);
let v = [
self.cx.const_uint_big(llty, range.start),
self.cx.const_uint_big(llty, range.end.wrapping_add(1)),
];
llvm::LLVMSetMetadata(
load,
llvm::MD_range as c_uint,
llvm::LLVMMDNodeInContext(self.cx.llcx, v.as_ptr(), v.len() as c_uint),
);
}
}

@rust-lang/wg-llvm might have some guesses here? Not sure why it would be incremental-related, though.

@DianQK
Copy link
Member

DianQK commented Aug 3, 2024

It's weird. My guess is that it's due to some LLVM Passes.

@nikic
Copy link
Contributor

nikic commented Aug 3, 2024

My first guess here would be a bug in getMostGenericRange(), but at least the basic case seems to work correctly: https://llvm.godbolt.org/z/sYY11P6Tc

@seritools
Copy link
Contributor Author

Making progress on figuring out the minimal code to comment out to successfully compile again, on the way I've now got this:

Intervals are contiguous
!40 = !{i8 -20, i8 -17, i8 4, i8 -20}
rustc-LLVM ERROR: Broken module found, compilation aborted!
Pass 'Early If-Conversion' is not initialized.
Verify if there is a pass dependency cycle.
Required Passes:
        Machine Branch Probability Analysis
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
        Machine Module Information
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
        Error: Required pass not found! Possible causes:
                - Pass misconfiguration (e.g.: missing macros)
                - Corruption of the global PassRegistry
Pass '

@seritools
Copy link
Contributor Author

seritools commented Aug 3, 2024

Fully-minimized repro: https://github.com/seritools/ripferris

Do note the Cargo.toml release profile settings. Run with cargo build --release to repro.

// if this function is not commented out, ferris dies :c
pub fn kill_ferris(a: &Outer, b: &Outer) -> bool {
    a == b
}

#[derive(PartialEq)]
pub enum Inner1 {
    A,
    B = 0x7F,
}

#[derive(PartialEq)]
pub enum Inner2 {
    C = 0x80,
    D,
}

#[derive(PartialEq)]
pub enum Inner3 {
    E,
    F,
}

#[derive(PartialEq)]
pub enum Outer {
    Inner3(Inner3),
    Inner2(Inner2),
    Inner1(Inner1),
}

with

[profile.release]
incremental = true
Intervals are contiguous
!10 = !{i8 -128, i8 -126, i8 0, i8 -128}
in function _ZN9ripferris11kill_ferris17h99c74ef3cc576d2cE
rustc-LLVM ERROR: Broken function found, compilation aborted!

Notes:

  • Reordering the enum variants in Outer fixes it.
  • Reducing the discriminant value of B or C fixes it.
  • incremental = false fixes it.

@DianQK
Copy link
Member

DianQK commented Aug 3, 2024

Thanks!

@seritools
Copy link
Contributor Author

seritools commented Aug 3, 2024

Reduced repro even further, with the minimal B and C values (thx @shepmaster). Reduce them any further and the error is gone. Also removed the slice and replaced with just an equals check (since the bisect pointed to a PartialEq check anyway)

@DianQK
Copy link
Member

DianQK commented Aug 3, 2024

Very interesting, I can trigger random crashes locally at stage 1, for example:

Intervals are overlapping
!18 = !{i8 -27, i8 -24, i8 127, i8 -17}
Intervals are overlapping
!18 = !{i8 -27, i8 -24, i8 127, i8 -17}
in function _ZN53_$LT$T$u20$as$u20$core..slice..cmp..SliceContains$GT$14slice_contains17hc33dc5e9736f5917E
rustc-LLVM ERROR: Broken function found, compilation aborted!
rustc: /home/dianqk/rs/rust/src/llvm-project/llvm/include/llvm/ADT/DenseMap.h:1307: DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConst> &llvm::DenseMapIterator<const void *, const llvm::PassInfo *>::operator++() [KeyT = const void *, ValueT = const llvm::PassInfo *, KeyInfoT = llvm::DenseMapInfo<const void *>, Bucket = llvm::detail::DenseMapPair<const void *, const llvm::PassInfo *>, IsConst = false]: Assertion `isHandleInSync() && "invalid iterator access!"' failed.
./run.sh: line 3: 1670986 Aborted                 (core dumped) rustc +stage1 src/lib.rs --crate-type lib -Copt-level=2 -C debuginfo=0 --out-dir /home/dianqk/rs/working/ripferris/target/release/deps -C incremental=/home/dianqk/rs/working/ripferris/target/release/incremental -Ccodegen-units=2

@seritools
Copy link
Contributor Author

seritools commented Aug 3, 2024

Never really looked at LLVM IR before, but guessing by what @nikic posted with the !range metadata:

According to LLVM docs:

The pair a,b represents the range [a,b).
The range is allowed to wrap.
... and they must be non-contiguous.

It seems as if some part of the code(gen) doesn't consider the wraparound when representing as i8 correctly, and because of that doesn't consider 0x7F and 0x80 to be contiguous, leading to the LLVM error. By adjusting the discriminant values the error message can change between Intervals are overlapping and Intervals are contiguous.

The generated IR between 1.79.0 and 1.80.0 has changed significantly for incremental = true builds.

Rust 1.80.0, incremental = true:

; ModuleID = 'duqhpgcgzz5uc8dyf0qjrz9af'
source_filename = "duqhpgcgzz5uc8dyf0qjrz9af"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

; ripferris::kill_ferris
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, inaccessiblemem: readwrite) uwtable
define noundef zeroext i1 @_ZN9ripferris11kill_ferris17h99c74ef3cc576d2cE(ptr noalias nocapture noundef readonly align 1 dereferenceable(2) %0, ptr noalias nocapture noundef readonly align 1 dereferenceable(2) %1) unnamed_addr #0 {
start:
  tail call void @llvm.experimental.noalias.scope.decl(metadata !2)
  tail call void @llvm.experimental.noalias.scope.decl(metadata !5)
  %2 = load i8, ptr %0, align 1, !range !7, !alias.scope !2, !noalias !5, !noundef !8
  %3 = load i8, ptr %1, align 1, !range !7, !alias.scope !5, !noalias !2, !noundef !8
  %_5.i.i = icmp eq i8 %2, %3
  %4 = getelementptr inbounds i8, ptr %0, i64 1
  %5 = getelementptr inbounds i8, ptr %1, i64 1
  %_3.val.i.i.i = load i8, ptr %4, align 1, !range !9, !alias.scope !2, !noalias !5
  %_4.val.i.i.i = load i8, ptr %5, align 1, !range !9, !alias.scope !5, !noalias !2
  %_0.i.i.i.i = icmp eq i8 %_3.val.i.i.i, %_4.val.i.i.i
  %_0.sroa.0.0.shrunk.i.i = select i1 %_5.i.i, i1 %_0.i.i.i.i, i1 false
  ret i1 %_0.sroa.0.0.shrunk.i.i
}

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
declare void @llvm.experimental.noalias.scope.decl(metadata) #1

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, inaccessiblemem: readwrite) uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{!"rustc version 1.80.0 (051478957 2024-07-21)"}
!2 = !{!3}
!3 = distinct !{!3, !4, !"_ZN57_$LT$ripferris..Outer$u20$as$u20$core..cmp..PartialEq$GT$2eq17h77e2ba2e053f3aceE: %self"}
!4 = distinct !{!4, !"_ZN57_$LT$ripferris..Outer$u20$as$u20$core..cmp..PartialEq$GT$2eq17h77e2ba2e053f3aceE"}
!5 = !{!6}
!6 = distinct !{!6, !4, !"_ZN57_$LT$ripferris..Outer$u20$as$u20$core..cmp..PartialEq$GT$2eq17h77e2ba2e053f3aceE: %other"}
!7 = !{i8 0, i8 3}
!8 = !{}
!9 = !{i8 -128, i8 -126, i8 0, i8 -128}

Rust 1.80.0, incremental = false

; ModuleID = 'ripferris.66419103721d0e4a-cgu.0'
source_filename = "ripferris.66419103721d0e4a-cgu.0"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

; ripferris::kill_ferris
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable
define noundef zeroext i1 @_ZN9ripferris11kill_ferris17hfe68d666d6297f4cE(ptr noalias nocapture noundef readonly align 1 dereferenceable(2) %a, ptr noalias nocapture noundef readonly align 1 dereferenceable(2) %b) unnamed_addr #0 {
start:
  %a.val = load i8, ptr %a, align 1, !range !2, !noundef !3
  %0 = getelementptr inbounds i8, ptr %a, i64 1
  %a.val1 = load i8, ptr %0, align 1
  %b.val = load i8, ptr %b, align 1, !range !2, !noundef !3
  %1 = getelementptr inbounds i8, ptr %b, i64 1
  %b.val2 = load i8, ptr %1, align 1
  %_5.i = icmp eq i8 %a.val, %b.val
  %2 = icmp eq i8 %a.val1, %b.val2
  %spec.select.i = select i1 %_5.i, i1 %2, i1 false
  ret i1 %spec.select.i
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{!"rustc version 1.80.0 (051478957 2024-07-21)"}
!2 = !{i8 0, i8 3}
!3 = !{}

Rust 1.79.0, incremental = true

; ModuleID = '572zzncnlkt8fmud'
source_filename = "572zzncnlkt8fmud"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

; ripferris::kill_ferris
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable
define noundef zeroext i1 @_ZN9ripferris11kill_ferris17hfea6ce1318ba41a7E(ptr noalias nocapture noundef readonly align 1 dereferenceable(2) %0, ptr noalias nocapture noundef readonly align 1 dereferenceable(2) %1) unnamed_addr #0 {
start:
  %_3.val.i = load i8, ptr %0, align 1, !range !2, !noundef !3
  %2 = getelementptr inbounds i8, ptr %0, i64 1
  %_3.val1.i = load i8, ptr %2, align 1
  %_4.val.i = load i8, ptr %1, align 1, !range !2, !noundef !3
  %3 = getelementptr inbounds i8, ptr %1, i64 1
  %_4.val2.i = load i8, ptr %3, align 1
  %_5.i.i = icmp eq i8 %_3.val.i, %_4.val.i
  %_0.i.i.i = icmp eq i8 %_3.val1.i, %_4.val2.i
  %spec.select.i.i = select i1 %_5.i.i, i1 %_0.i.i.i, i1 false
  ret i1 %spec.select.i.i
}

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{!"rustc version 1.79.0 (129f3b996 2024-06-10)"}
!2 = !{i8 0, i8 3}
!3 = !{}

@seritools seritools changed the title Incremental compilation regression from 1.79 to 1.80: rustc-LLVM ERROR: Intervals are contiguous Incremental compilation regression from 1.79 to 1.80: rustc-LLVM ERROR: Intervals are contiguous/overlapping Aug 3, 2024
@DianQK
Copy link
Member

DianQK commented Aug 3, 2024

Ah, the minimal reproducible example is: https://llvm.godbolt.org/z/3vbrnjvPq

define i8 @foo(ptr %arg, i8 %arg1) {
bb:
  %i = load i8, ptr %arg, align 1, !range !{i8 127, i8 -20}
  %i2 = load i8, ptr %arg, align 1, !range !{i8 -27, i8 -24, i8 -20, i8 -17}
  %i3 = add i8 %i, %i2
  ret i8 %i3
}

(But I'm going to bed. 😴

@DianQK
Copy link
Member

DianQK commented Aug 3, 2024

IIUC, this should be Size > 2:

https://github.com/llvm/llvm-project/blob/ca3d4dfe0c8844a8010751c51600a3bd3f6f80a4/llvm/lib/IR/Metadata.cpp#L1323-L1333

@DianQK
Copy link
Member

DianQK commented Aug 4, 2024

Upstreamed issue: llvm/llvm-project#101859.

@rustbot claim

@nikic nikic added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. llvm-fixed-upstream Issue expected to be fixed by the next major LLVM upgrade, or backported fixes and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Aug 5, 2024
@DianQK
Copy link
Member

DianQK commented Aug 6, 2024

This can happen in any version: https://rust.godbolt.org/z/1zTxnWTj4.

bors added a commit to rust-lang-ci/rust that referenced this issue Aug 11, 2024
Update to LLVM 19 rc2

Update from ~rc1 to rc2.

Fixes rust-lang#128555.
bors added a commit to rust-lang-ci/rust that referenced this issue Aug 11, 2024
Update to LLVM 19 rc2

Update from ~rc1 to rc2.

Fixes rust-lang#128555.
bors added a commit to rust-lang-ci/rust that referenced this issue Aug 11, 2024
Update to LLVM 19 rc2

Update from ~rc1 to rc2.

Fixes rust-lang#128555.
@bors bors closed this as completed in 41dd149 Aug 11, 2024
RalfJung pushed a commit to RalfJung/miri that referenced this issue Aug 12, 2024
Update to LLVM 19 rc2

Update from ~rc1 to rc2.

Fixes rust-lang/rust#128555.
lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Aug 13, 2024
Update to LLVM 19 rc2

Update from ~rc1 to rc2.

Fixes rust-lang/rust#128555.
devnexen pushed a commit to devnexen/rust that referenced this issue Aug 13, 2024
Update to LLVM 19 rc2

Update from ~rc1 to rc2.

Fixes rust-lang#128555.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ llvm-fixed-upstream Issue expected to be fixed by the next major LLVM upgrade, or backported fixes T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants