rust-lang / rust-lang/rust

Reordered LLVM-IR bbs causing `FileCheck` failures on `aarch64-unknown-none`

Open
#127,395 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-LLVM A-testsuite C-bug O-AArch64 T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

This issue came to my attention as it happens on a custom target that we use on ferrocene to test aarch64-unknown-none. However, I was able to reproduce it here as well (on commit 9a21ac8e7ef) and it might cause some errors in the future

The FileCheck test on tests/codegen/vec_pop_push_noop.rs will fail if the basic blocks of the LLVM-IR for the noop function are reordered in such a way that the returning block is not at the end.

This is the IR on x86_64-unknown-linux-gnu (which passes the test):

; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, inaccessiblemem: write) uwtable
define void @noop(ptr noalias nocapture noundef readonly align 8 dereferenceable(24) %v) unnamed_addr #2 personality ptr @rust_eh_personality {
start:
  %0 = getelementptr inbounds i8, ptr %v, i64 16
  %_4 = load i64, ptr %0, align 8, !noundef !3
  %1 = icmp eq i64 %_4, 0
  br i1 %1, label %bb1, label %"_ZN5alloc3vec16Vec$LT$T$C$A$GT$4push17h6b95231b811ede1dE.exit"

"_ZN5alloc3vec16Vec$LT$T$C$A$GT$4push17h6b95231b811ede1dE.exit": ; preds = %start
  %2 = add i64 %_4, -1
  %_7 = load i64, ptr %v, align 8, !noundef !3
  %_5 = icmp ult i64 %2, %_7
  tail call void @llvm.assume(i1 %_5)
  br label %bb1

bb1:                                              ; preds = %start, %"_ZN5alloc3vec16Vec$LT$T$C$A$GT$4push17h6b95231b811ede1dE.exit"
  ret void
}

And this is the IR on aarch64-unknown-none

; Function Attrs: mustprogress nofree norecurse noredzone nosync nounwind willreturn memory(argmem: read, inaccessiblemem: write)
define dso_local void @noop(ptr noalias nocapture noundef readonly align 8 dereferenceable(24) %v) unnamed_addr #3 {
start:
  %0 = getelementptr inbounds i8, ptr %v, i64 16
  %_2.i = load i64, ptr %0, align 8, !alias.scope !19, !noundef !1
  %.not = icmp eq i64 %_2.i, 0
  br i1 %.not, label %bb3, label %bb7

bb3:                                              ; preds = %start, %bb7
  ret void

bb7:                                              ; preds = %start
  %1 = add i64 %_2.i, -1
  %2 = load i64, ptr %v, align 8, !noundef !1
  %cond.i = icmp ult i64 %1, %2
  tail call void @llvm.assume(i1 %cond.i)
  br label %bb3
}

This is the config.toml I used:

[llvm]
download-ci-llvm = false
assertions = true
static-libstdcpp = true

[build]
host = ["x86_64-unknown-linux-gnu"]
target = ["aarch64-unknown-none"]
docs = false
extended = true
tools = [
   "cargo",
   "clippy",
   "rustdoc",
   "rustfmt",
   "rust-analyzer",
   "rust-analyzer-proc-macro-srv",
   "analysis",
   "src",
   "rust-demangler",  ]
sanitizers = true
cargo-native-static = true
metrics = false

[rust]
debug-assertions = true
channel = "dev"
lld = false
remap-debuginfo = true

[dist]

I had to update the vec_pop_push_noop.rs test so it uses alloc instead of std:

//@ compile-flags: -O
#![no_std]
#![crate_type = "lib"]
extern crate alloc;
#[no_mangle]
// CHECK-LABEL: @noop(
pub fn noop(v: &mut alloc::vec::Vec<u8>) {
    // CHECK-NOT: grow_one
    // CHECK-NOT: call
    // CHECK: tail call void @llvm.assume
    // CHECK-NOT: grow_one
    // CHECK-NOT: call
    // CHECK: ret
    if let Some(x) = v.pop() {
        v.push(x)
    }
}

#[no_mangle]
// CHECK-LABEL: @push_byte(
pub fn push_byte(v: &mut alloc::vec::Vec<u8>) {
    // CHECK: call {{.*}}grow_one
    v.push(3);
}

And finally run:

$ ./x.py test tests/codegen/vec_pop_push_noop.rs

This is the error:

./tests/codegen/vec_pop_push_noop.rs:13:12: error: CHECK: expected string not found in input
 // CHECK: ret
           ^
./vec_pop_push_noop.ll:270:29: note: scanning from here
 tail call void @llvm.assume(i1 %cond.i)
                            ^
./vec_pop_push_noop.ll:274:21: note: possible intended match here
; Function Attrs: noredzone nounwind
                    ^

Input file: ./vec_pop_push_noop.ll
Check file: ./tests/codegen/vec_pop_push_noop.rs

-dump-input=help explains the following input dump.

Input was: ...

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with tests/codegen/vec_pop_push_noop.rs and reproduce the failure with ./x.py test tests/codegen/vec_pop_push_noop.rs using the reported aarch64-unknown-none setup. Inspect the generated vec_pop_push_noop.ll and the FileCheck directives around noop; done means the test passes despite the reordered LLVM-IR basic blocks.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers, testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.