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

MIR inlining leads to LLVM error around box_free #50041

Closed
glandium opened this issue Apr 18, 2018 · 7 comments
Closed

MIR inlining leads to LLVM error around box_free #50041

glandium opened this issue Apr 18, 2018 · 7 comments

Comments

@glandium
Copy link
Contributor

Context: In order to experiment with an Alloc-aware Box, I was preparing to modify the box_free lang item signature, and my first step was to ensure MIR passes the right type to begin with, as noted in

// box_free takes a Box, but is defined with a *mut T, inlining
// needs to generate the cast.
// FIXME: we should probably just generate correct MIR in the first place...

Legitimately, I assumed that the MIR inline code was doing the right thing, so I mimicked it in elaborate_drops.rs. The resulting code actually works fine, as far as completing the 3 stages of rustc bootstrapping is involved.

But before going the box_free route for the Alloc-aware Box, I first tried removing the special handling of Box's Drop, trying to leave it to boxed.rs, shortcutting the box_free lang item. This didn't go well, and produced a stage 1 compiler that would crash on a bad free in libsyntax's ThinVec. From which I derived a small test case that would exhibit the problem with my code. Anyways, I was going well over my head with this approach, thus switched to the box_free signature change.

So, what's the deal with this issue, will you ask? Well, it turns out that my MIR changes, essentially copied from MIR inlining, while they worked to produce an apparently working compiler, failed to compile that reduced testcase with an LLVM ERROR. I was wondering if I did something significantly different from what the MIT inlining pass was doing, so I tried to trigger it manually (since it's not enabled by default), and after some trial and error, got it to happen on a plain nightly compiler, with the following reduced testcase:

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

#[lang = "owned_box"]
pub struct Box<T: ?Sized>(*mut T);

impl<T: ?Sized> Drop for Box<T> {
    fn drop(&mut self) {
    }
}

#[lang = "box_free"]
#[inline(always)]
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
    dealloc(ptr)
}

#[inline(never)]
fn dealloc<T: ?Sized>(_: *mut T) {
}

pub struct Foo<T>(T);

pub fn foo(a: Option<Box<Foo<usize>>>) -> usize {
    let f = match a {
        None => Foo(0),
        Some(vec) => *vec,
    };
    f.0
}

Building with rustc +nightly -Z mir_opt_level=2 test.rs yields:

Instruction does not dominate all uses!
  %14 = load i64*, i64** %13, align 8
  call void @_ZN4test7dealloc17hb146efc385cf7afbE(i64* %14)
LLVM ERROR: Broken function found, compilation aborted!

(Note the #[inline(always)] is only there to force MIR inlining to happen without having to go over the required threshold ; liballoc's box_free has #[inline] ; similarly, the #[inline(never)] on dealloc avoids inlining of dealloc, to limit the effects on the MIR)

Interestingly enough, --emit mir and --emit llvm-ir fail with the same error. The former outputs a truncated MIR (truncated at the entry of the first basic block), and the latter outputs nothing.

@glandium
Copy link
Contributor Author

glandium commented Apr 18, 2018

This is what rustc.foo.002-026.PreTrans.after.mir from a run with -Z dump-mir=all looks like:

// MIR for `foo`
// source = MirSource { def_id: DefId(0/0:10 ~ test[8787]::foo[0]), promoted: None }
// pass_name = PreTrans
// disambiguator = after

fn foo(_1: core::option::Option<Box<Foo<usize>>>) -> usize{
    let mut _0: usize;                   // return place
    scope 1 {
        let _2: Foo<usize>;              // "f" in scope 1 at test.rs:26:9: 26:10
    }
    scope 2 {
    }
    scope 3 {
        let _4: Box<Foo<usize>>;         // "vec" in scope 3 at test.rs:28:14: 28:17
    }
    scope 4 {
    }
    let mut _3: isize;
    let mut _5: isize;
    let mut _6: Foo<usize>;
    let mut _7: usize;
    let mut _8: bool;
    let mut _9: bool;
    let mut _10: ();
    let mut _11: isize;
    let mut _12: &mut Foo<usize>;
    let mut _13: *mut Foo<usize>;

    bb0: {                              
        _8 = const false;                // bb0[0]: scope 0 at test.rs:26:9: 26:10
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:26:9: 26:10
                                         // + ty: bool
                                         // + literal: const false
        _9 = const false;                // bb0[1]: scope 0 at test.rs:26:9: 26:10
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:26:9: 26:10
                                         // + ty: bool
                                         // + literal: const false
        _9 = const true;                 // bb0[2]: scope 0 at test.rs:26:9: 26:10
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(1)))
                                         // mir::Constant
                                         // + span: test.rs:26:9: 26:10
                                         // + ty: bool
                                         // + literal: const true
        StorageLive(_2);                 // bb0[3]: scope 0 at test.rs:26:9: 26:10
        _3 = discriminant(_1);           // bb0[4]: scope 0 at test.rs:26:13: 29:6
        _5 = discriminant(_1);           // bb0[5]: scope 0 at test.rs:27:9: 27:13
        switchInt(move _5) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // bb0[6]: scope 0 at test.rs:27:9: 27:13
    }

    bb1: {                              
        (_2.0: usize) = const 0usize;    // bb1[0]: scope 0 at test.rs:27:17: 27:23
                                         // ty::Const
                                         // + ty: usize
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:27:21: 27:22
                                         // + ty: usize
                                         // + literal: const 0usize
        goto -> bb6;                     // bb1[1]: scope 0 at test.rs:26:13: 29:6
    }

    bb2: {                              
        unreachable;                     // bb2[0]: scope 0 at test.rs:31:2: 31:2
    }

    bb3: {                              
        StorageLive(_4);                 // bb3[0]: scope 0 at test.rs:28:14: 28:17
        _9 = const false;                // bb3[1]: scope 0 at test.rs:28:14: 28:17
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:28:14: 28:17
                                         // + ty: bool
                                         // + literal: const false
        _8 = const true;                 // bb3[2]: scope 0 at test.rs:28:14: 28:17
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(1)))
                                         // mir::Constant
                                         // + span: test.rs:28:14: 28:17
                                         // + ty: bool
                                         // + literal: const true
        _4 = move ((_1 as Some).0: Box<Foo<usize>>); // bb3[3]: scope 0 at test.rs:28:14: 28:17
        StorageLive(_6);                 // bb3[4]: scope 3 at test.rs:28:22: 28:26
        _6 = move (*_4);                 // bb3[5]: scope 3 at test.rs:28:22: 28:26
        _2 = move _6;                    // bb3[6]: scope 3 at test.rs:28:22: 28:26
        StorageDead(_6);                 // bb3[7]: scope 3 at test.rs:28:25: 28:26
        goto -> bb6;                     // bb3[8]: scope 0 at test.rs:26:13: 29:6
    }

    bb4: {                              
        _8 = const false;                // bb4[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        StorageDead(_4);                 // bb4[1]: scope 0 at test.rs:29:5: 29:6
        StorageLive(_7);                 // bb4[2]: scope 1 at test.rs:30:5: 30:8
        _7 = (_2.0: usize);              // bb4[3]: scope 1 at test.rs:30:5: 30:8
        _0 = move _7;                    // bb4[4]: scope 1 at test.rs:30:5: 30:8
        StorageDead(_7);                 // bb4[5]: scope 1 at test.rs:30:7: 30:8
        StorageDead(_2);                 // bb4[6]: scope 0 at test.rs:31:1: 31:2
        _11 = discriminant(_1);          // bb4[7]: scope 0 at test.rs:31:1: 31:2
        switchInt(move _11) -> [1isize: bb8, otherwise: bb10]; // bb4[8]: scope 0 at test.rs:31:1: 31:2
    }

    bb5: {                              
        _8 = const false;                // bb5[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        _12 = &mut (*_4);                // bb5[1]: scope 0 at test.rs:29:5: 29:6
        _13 = move _12 as *mut Foo<usize> (Misc); // bb5[2]: scope 0 at test.rs:29:5: 29:6
        _10 = const dealloc(move _13) -> bb4; // bb5[3]: scope 4 at test.rs:16:5: 16:17
                                         // ty::Const
                                         // + ty: fn(*mut Foo<usize>) {dealloc::<Foo<usize>>}
                                         // + val: Value(ByVal(Undef))
                                         // mir::Constant
                                         // + span: test.rs:16:5: 16:12
                                         // + ty: fn(*mut Foo<usize>) {dealloc::<Foo<usize>>}
                                         // + literal: const dealloc
    }

    bb6: {                              
        switchInt(_8) -> [false: bb4, otherwise: bb5]; // bb6[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb7: {                              
        return;                          // bb7[0]: scope 0 at test.rs:31:2: 31:2
    }

    bb8: {                              
        switchInt(_9) -> [false: bb7, otherwise: bb9]; // bb8[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb9: {                              
        _9 = const false;                // bb9[0]: scope 0 at test.rs:31:1: 31:2
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:31:1: 31:2
                                         // + ty: bool
                                         // + literal: const false
        drop(((_1 as Some).0: Box<Foo<usize>>)) -> bb7; // bb9[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb10: {                             
        drop(_1) -> bb7;                 // bb10[0]: scope 0 at test.rs:31:1: 31:2
    }
}

Edit: and what the llvm-ir, as disassembled from -C save-temps output, looks like:

; ModuleID = 'test.test1.rcgu.no-opt.bc'
source_filename = "test1-8787f43e282added376259c1adb08b80.rs"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%"core::option::Option<Box<Foo<usize>>>" = type { [0 x i64], i64, [1 x i64] }
%"core::option::Option<Box<Foo<usize>>>::Some" = type { [1 x i64], i64*, [0 x i64] }

; Function Attrs: noinline uwtable
define void @_ZN4test7dealloc17hb146efc385cf7afbE(i64*) unnamed_addr #0 {
  ret void
}

; Function Attrs: uwtable
define i64 @_ZN4test3foo17h5eafaec26cbe1846E(%"core::option::Option<Box<Foo<usize>>>"* noalias nocapture dereferenceable(16)) unnamed_addr #1 {
  %2 = alloca i8, align 1
  %3 = alloca i8, align 1
  %4 = alloca i64, align 8
  store i8 0, i8* %3, align 1
  store i8 0, i8* %2, align 1
  store i8 1, i8* %2, align 1
  %5 = bitcast %"core::option::Option<Box<Foo<usize>>>"* %0 to i64*
  %6 = load i64, i64* %5, align 8, !range !0
  %7 = bitcast %"core::option::Option<Box<Foo<usize>>>"* %0 to i64*
  %8 = load i64, i64* %7, align 8, !range !0
  switch i64 %8, label %10 [
    i64 0, label %9
    i64 1, label %11
  ]

; <label>:9:                                      ; preds = %1
  store i64 0, i64* %4, align 8
  br label %21

; <label>:10:                                     ; preds = %1
  unreachable

; <label>:11:                                     ; preds = %1
  store i8 0, i8* %2, align 1
  store i8 1, i8* %3, align 1
  %12 = bitcast %"core::option::Option<Box<Foo<usize>>>"* %0 to %"core::option::Option<Box<Foo<usize>>>::Some"*
  %13 = getelementptr inbounds %"core::option::Option<Box<Foo<usize>>>::Some", %"core::option::Option<Box<Foo<usize>>>::Some"* %12, i32 0, i32 1
  %14 = load i64*, i64** %13, align 8
  %15 = load i64, i64* %14, align 8
  store i64 %15, i64* %4, align 8
  br label %21

; <label>:16:                                     ; preds = %21, %20
  store i8 0, i8* %3, align 1
  %17 = load i64, i64* %4, align 8
  %18 = bitcast %"core::option::Option<Box<Foo<usize>>>"* %0 to i64*
  %19 = load i64, i64* %18, align 8, !range !0
  switch i64 %19, label %31 [
    i64 1, label %25
  ]

; <label>:20:                                     ; preds = %21
  store i8 0, i8* %3, align 1
  call void @_ZN4test7dealloc17hb146efc385cf7afbE(i64* %14)
  br label %16

; <label>:21:                                     ; preds = %11, %9
  %22 = load i8, i8* %3, align 1, !range !1
  %23 = trunc i8 %22 to i1
  br i1 %23, label %20, label %16

; <label>:24:                                     ; preds = %31, %28, %25
  ret i64 %17

; <label>:25:                                     ; preds = %16
  %26 = load i8, i8* %2, align 1, !range !1
  %27 = trunc i8 %26 to i1
  br i1 %27, label %28, label %24

; <label>:28:                                     ; preds = %25
  store i8 0, i8* %2, align 1
  %29 = bitcast %"core::option::Option<Box<Foo<usize>>>"* %0 to %"core::option::Option<Box<Foo<usize>>>::Some"*
  %30 = getelementptr inbounds %"core::option::Option<Box<Foo<usize>>>::Some", %"core::option::Option<Box<Foo<usize>>>::Some"* %29, i32 0, i32 1
  call void @_ZN4core3ptr13drop_in_place17hc149ec1a0960208eE(i64** %30)
  br label %24

; <label>:31:                                     ; preds = %16
  call void @_ZN4core3ptr13drop_in_place17h2fef1d2b45619d3dE(%"core::option::Option<Box<Foo<usize>>>"* %0)
  br label %24
}

declare void @_ZN4core3ptr13drop_in_place17h2fef1d2b45619d3dE(%"core::option::Option<Box<Foo<usize>>>"*) unnamed_addr #2

declare void @_ZN4core3ptr13drop_in_place17hc149ec1a0960208eE(i64**) unnamed_addr #2

attributes #0 = { noinline uwtable "probe-stack"="__rust_probestack" }
attributes #1 = { uwtable "probe-stack"="__rust_probestack" }
attributes #2 = { "probe-stack"="__rust_probestack" }

!0 = !{i64 0, i64 2}
!1 = !{i8 0, i8 2}

@glandium glandium changed the title MIT inlining leads to LLVM error around box_free MIR inlining leads to LLVM error around box_free Apr 18, 2018
@glandium
Copy link
Contributor Author

The problem is that the code path bb1->bb9->bb21->bb20 in IR, corresponding to bb0->bb1->bb6->bb5 in MIR, is impossible, yet exists. And in that code path, _4 in MIR, %14 in IR, is never initialized, and that's what LLVM doesn't like. I guess one way to look at is it to wonder why bb6 in MIR has a switch in the first place.

@glandium
Copy link
Contributor Author

And the answer to that last question is false edges, according to the following MIR from the mir_map pass:

// MIR for `foo`
// source = MirSource { def_id: DefId(0/0:10 ~ test[8787]::foo[0]), promoted: None }
// pass_name = mir_map
// disambiguator = 0

fn foo(_1: core::option::Option<Box<Foo<usize>>>) -> usize{
    let mut _0: usize;                   // return place
    scope 1 {
        let _2: Foo<usize>;              // "f" in scope 1 at test.rs:26:9: 26:10
    }
    scope 2 {
    }
    scope 3 {
        let _4: Box<Foo<usize>>;         // "vec" in scope 3 at test.rs:28:14: 28:17
    }
    let mut _3: isize;
    let mut _5: isize;
    let mut _6: Foo<usize>;
    let mut _7: usize;

    bb0: {                              
        StorageLive(_2);                 // bb0[0]: scope 0 at test.rs:26:9: 26:10
        _3 = discriminant(_1);           // bb0[1]: scope 0 at test.rs:26:13: 29:6
        _5 = discriminant(_1);           // bb0[2]: scope 0 at test.rs:27:9: 27:13
        switchInt(move _5) -> [0isize: bb7, 1isize: bb8, otherwise: bb9]; // bb0[3]: scope 0 at test.rs:27:9: 27:13
    }

    bb1: {                               // cleanup
        resume;                          // bb1[0]: scope 0 at test.rs:25:1: 31:2
    }

    bb2: {                              
        _2 = Foo<usize>::{{constructor}}(const 0usize,); // bb2[0]: scope 0 at test.rs:27:17: 27:23
                                         // ty::Const
                                         // + ty: usize
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:27:21: 27:22
                                         // + ty: usize
                                         // + literal: const 0usize
        goto -> bb12;                    // bb2[1]: scope 0 at test.rs:26:13: 29:6
    }

    bb3: {                              
        StorageLive(_6);                 // bb3[0]: scope 3 at test.rs:28:22: 28:26
        _6 = move (*_4);                 // bb3[1]: scope 3 at test.rs:28:22: 28:26
        _2 = move _6;                    // bb3[2]: scope 3 at test.rs:28:22: 28:26
        StorageDead(_6);                 // bb3[3]: scope 3 at test.rs:28:25: 28:26
        goto -> bb12;                    // bb3[4]: scope 0 at test.rs:26:13: 29:6
    }

    bb4: {                              
        falseEdges -> [real: bb10, imaginary: bb5]; // bb4[0]: scope 0 at test.rs:27:9: 27:13
    }

    bb5: {                              
        falseEdges -> [real: bb11, imaginary: bb6]; // bb5[0]: scope 0 at test.rs:28:9: 28:18
    }

    bb6: {                              
        unreachable;                     // bb6[0]: scope 0 at test.rs:26:13: 29:6
    }

    bb7: {                              
        goto -> bb4;                     // bb7[0]: scope 0 at test.rs:27:9: 27:13
    }

    bb8: {                              
        goto -> bb5;                     // bb8[0]: scope 0 at test.rs:28:9: 28:18
    }

    bb9: {                              
        unreachable;                     // bb9[0]: scope 0 at test.rs:31:2: 31:2
    }

    bb10: {                             
        goto -> bb2;                     // bb10[0]: scope 0 at test.rs:27:9: 27:13
    }

    bb11: {                             
        StorageLive(_4);                 // bb11[0]: scope 0 at test.rs:28:14: 28:17
        _4 = move ((_1 as Some).0: Box<Foo<usize>>); // bb11[1]: scope 0 at test.rs:28:14: 28:17
        goto -> bb3;                     // bb11[2]: scope 0 at test.rs:28:9: 28:18
    }

    bb12: {                             
        drop(_4) -> [return: bb24, unwind: bb21]; // bb12[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb13: {                              // cleanup
        goto -> bb1;                     // bb13[0]: scope 0 at test.rs:25:1: 31:2
    }

    bb14: {                              // cleanup
        drop(_1) -> bb13;                // bb14[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb15: {                              // cleanup
        goto -> bb14;                    // bb15[0]: scope 0 at test.rs:25:1: 31:2
    }

    bb16: {                              // cleanup
        goto -> bb15;                    // bb16[0]: scope 0 at test.rs:25:49: 31:2
    }

    bb17: {                              // cleanup
        goto -> bb16;                    // bb17[0]: scope 0 at test.rs:25:49: 31:2
    }

    bb18: {                              // cleanup
        goto -> bb17;                    // bb18[0]: scope 0 at test.rs:25:49: 31:2
    }

    bb19: {                              // cleanup
        goto -> bb18;                    // bb19[0]: scope 0 at test.rs:25:49: 31:2
    }

    bb20: {                              // cleanup
        goto -> bb19;                    // bb20[0]: scope 0 at test.rs:25:49: 31:2
    }

    bb21: {                              // cleanup
        goto -> bb20;                    // bb21[0]: scope 0 at test.rs:25:49: 31:2
    }

    bb22: {                              // cleanup
        drop(_4) -> bb21;                // bb22[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb23: {                              // cleanup
        goto -> bb22;                    // bb23[0]: scope 0 at test.rs:26:13: 29:6
    }

    bb24: {                             
        StorageDead(_4);                 // bb24[0]: scope 0 at test.rs:29:5: 29:6
        StorageLive(_7);                 // bb24[1]: scope 1 at test.rs:30:5: 30:8
        _7 = (_2.0: usize);              // bb24[2]: scope 1 at test.rs:30:5: 30:8
        _0 = move _7;                    // bb24[3]: scope 1 at test.rs:30:5: 30:8
        StorageDead(_7);                 // bb24[4]: scope 1 at test.rs:30:7: 30:8
        StorageDead(_2);                 // bb24[5]: scope 0 at test.rs:31:1: 31:2
        drop(_1) -> [return: bb25, unwind: bb1]; // bb24[6]: scope 0 at test.rs:31:1: 31:2
    }

    bb25: {                             
        goto -> bb26;                    // bb25[0]: scope 0 at test.rs:31:2: 31:2
    }

    bb26: {                             
        return;                          // bb26[0]: scope 0 at test.rs:31:2: 31:2
    }
}

@glandium
Copy link
Contributor Author

Actually, the path bb0->bb7->bb4->bb10->bb12 has drop(_4) without _4 ever being initialized, but that's pre-elaborate-drops, and I hear drop is different then, so I don't know if it bad or not.

@glandium
Copy link
Contributor Author

The weird switch that eventually causes the LLVM problem is added by the elaborate-drops pass. The MIR after that phase looks like the following:

// MIR for `foo`
// source = MirSource { def_id: DefId(0/0:10 ~ test[8787]::foo[0]), promoted: None }
// pass_name = ElaborateDrops
// disambiguator = after

fn foo(_1: core::option::Option<Box<Foo<usize>>>) -> usize{
    let mut _0: usize;                   // return place
    scope 1 {
        let _2: Foo<usize>;              // "f" in scope 1 at test.rs:26:9: 26:10
    }
    scope 2 {
    }
    scope 3 {
        let _4: Box<Foo<usize>>;         // "vec" in scope 3 at test.rs:28:14: 28:17
    }
    let mut _3: isize;
    let mut _5: isize;
    let mut _6: Foo<usize>;
    let mut _7: usize;
    let mut _8: bool;
    let mut _9: bool;
    let mut _10: ();
    let mut _11: ();
    let mut _12: isize;
    let mut _13: isize;
    let mut _14: isize;

    bb0: {                              
        _8 = const false;                // bb0[0]: scope 0 at test.rs:26:9: 26:10
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:26:9: 26:10
                                         // + ty: bool
                                         // + literal: const false
        _9 = const false;                // bb0[1]: scope 0 at test.rs:26:9: 26:10
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:26:9: 26:10
                                         // + ty: bool
                                         // + literal: const false
        _9 = const true;                 // bb0[2]: scope 0 at test.rs:26:9: 26:10
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(1)))
                                         // mir::Constant
                                         // + span: test.rs:26:9: 26:10
                                         // + ty: bool
                                         // + literal: const true
        StorageLive(_2);                 // bb0[3]: scope 0 at test.rs:26:9: 26:10
        _3 = discriminant(_1);           // bb0[4]: scope 0 at test.rs:26:13: 29:6
        _5 = discriminant(_1);           // bb0[5]: scope 0 at test.rs:27:9: 27:13
        switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // bb0[6]: scope 0 at test.rs:27:9: 27:13
    }

    bb1: {                               // cleanup
        resume;                          // bb1[0]: scope 0 at test.rs:25:1: 31:2
    }

    bb2: {                              
        _2 = Foo<usize>::{{constructor}}(const 0usize,); // bb2[0]: scope 0 at test.rs:27:17: 27:23
                                         // ty::Const
                                         // + ty: usize
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:27:21: 27:22
                                         // + ty: usize
                                         // + literal: const 0usize
        goto -> bb5;                     // bb2[1]: scope 0 at test.rs:26:13: 29:6
    }

    bb3: {                              
        unreachable;                     // bb3[0]: scope 0 at test.rs:31:2: 31:2
    }

    bb4: {                              
        StorageLive(_4);                 // bb4[0]: scope 0 at test.rs:28:14: 28:17
        _9 = const false;                // bb4[1]: scope 0 at test.rs:28:14: 28:17
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:28:14: 28:17
                                         // + ty: bool
                                         // + literal: const false
        _8 = const true;                 // bb4[2]: scope 0 at test.rs:28:14: 28:17
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(1)))
                                         // mir::Constant
                                         // + span: test.rs:28:14: 28:17
                                         // + ty: bool
                                         // + literal: const true
        _4 = move ((_1 as Some).0: Box<Foo<usize>>); // bb4[3]: scope 0 at test.rs:28:14: 28:17
        StorageLive(_6);                 // bb4[4]: scope 3 at test.rs:28:22: 28:26
        _6 = move (*_4);                 // bb4[5]: scope 3 at test.rs:28:22: 28:26
        _2 = move _6;                    // bb4[6]: scope 3 at test.rs:28:22: 28:26
        StorageDead(_6);                 // bb4[7]: scope 3 at test.rs:28:25: 28:26
        goto -> bb5;                     // bb4[8]: scope 0 at test.rs:26:13: 29:6
    }

    bb5: {                              
        goto -> bb13;                    // bb5[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb6: {                               // cleanup
        goto -> bb20;                    // bb6[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb7: {                              
        _8 = const false;                // bb7[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        StorageDead(_4);                 // bb7[1]: scope 0 at test.rs:29:5: 29:6
        StorageLive(_7);                 // bb7[2]: scope 1 at test.rs:30:5: 30:8
        _7 = (_2.0: usize);              // bb7[3]: scope 1 at test.rs:30:5: 30:8
        _0 = move _7;                    // bb7[4]: scope 1 at test.rs:30:5: 30:8
        StorageDead(_7);                 // bb7[5]: scope 1 at test.rs:30:7: 30:8
        StorageDead(_2);                 // bb7[6]: scope 0 at test.rs:31:1: 31:2
        goto -> bb37;                    // bb7[7]: scope 0 at test.rs:31:1: 31:2
    }

    bb8: {                              
        return;                          // bb8[0]: scope 0 at test.rs:31:2: 31:2
    }

    bb9: {                              
        _8 = const false;                // bb9[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        _10 = const box_free(move _4) -> bb7; // bb9[1]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: unsafe fn(*mut Foo<usize>) {box_free::<Foo<usize>>}
                                         // + val: Value(ByVal(Undef))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: unsafe fn(*mut Foo<usize>) {box_free::<Foo<usize>>}
                                         // + literal: const box_free
    }

    bb10: {                             
        switchInt(_8) -> [false: bb7, otherwise: bb9]; // bb10[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb11: {                              // cleanup
        _8 = const false;                // bb11[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        _11 = const box_free(move _4) -> bb6; // bb11[1]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: unsafe fn(*mut Foo<usize>) {box_free::<Foo<usize>>}
                                         // + val: Value(ByVal(Undef))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: unsafe fn(*mut Foo<usize>) {box_free::<Foo<usize>>}
                                         // + literal: const box_free
    }

    bb12: {                              // cleanup
        switchInt(_8) -> [false: bb6, otherwise: bb11]; // bb12[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb13: {                             
        goto -> bb10;                    // bb13[0]: scope 0 at test.rs:29:5: 29:6
    }

    bb14: {                              // cleanup
        goto -> bb1;                     // bb14[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb15: {                              // cleanup
        goto -> bb18;                    // bb15[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb16: {                              // cleanup
        drop(((_1 as Some).0: Box<Foo<usize>>)) -> bb14; // bb16[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb17: {                              // cleanup
        _9 = const false;                // bb17[0]: scope 0 at test.rs:31:1: 31:2
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:31:1: 31:2
                                         // + ty: bool
                                         // + literal: const false
        goto -> bb16;                    // bb17[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb18: {                              // cleanup
        switchInt(_9) -> [false: bb14, otherwise: bb17]; // bb18[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb19: {                              // cleanup
        drop(_1) -> bb14;                // bb19[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb20: {                              // cleanup
        _12 = discriminant(_1);          // bb20[0]: scope 0 at test.rs:31:1: 31:2
        switchInt(move _12) -> [1isize: bb15, otherwise: bb19]; // bb20[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb21: {                             
        goto -> bb8;                     // bb21[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb22: {                              // cleanup
        goto -> bb1;                     // bb22[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb23: {                              // cleanup
        goto -> bb26;                    // bb23[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb24: {                              // cleanup
        drop(((_1 as Some).0: Box<Foo<usize>>)) -> bb22; // bb24[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb25: {                              // cleanup
        _9 = const false;                // bb25[0]: scope 0 at test.rs:31:1: 31:2
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:31:1: 31:2
                                         // + ty: bool
                                         // + literal: const false
        goto -> bb24;                    // bb25[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb26: {                              // cleanup
        switchInt(_9) -> [false: bb22, otherwise: bb25]; // bb26[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb27: {                              // cleanup
        goto -> bb30;                    // bb27[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb28: {                              // cleanup
        drop(((_1 as Some).0: Box<Foo<usize>>)) -> bb22; // bb28[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb29: {                              // cleanup
        _9 = const false;                // bb29[0]: scope 0 at test.rs:31:1: 31:2
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:31:1: 31:2
                                         // + ty: bool
                                         // + literal: const false
        goto -> bb28;                    // bb29[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb30: {                              // cleanup
        switchInt(_9) -> [false: bb22, otherwise: bb29]; // bb30[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb31: {                             
        goto -> bb34;                    // bb31[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb32: {                             
        drop(((_1 as Some).0: Box<Foo<usize>>)) -> [return: bb21, unwind: bb22]; // bb32[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb33: {                             
        _9 = const false;                // bb33[0]: scope 0 at test.rs:31:1: 31:2
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:31:1: 31:2
                                         // + ty: bool
                                         // + literal: const false
        goto -> bb32;                    // bb33[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb34: {                             
        switchInt(_9) -> [false: bb21, otherwise: bb33]; // bb34[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb35: {                             
        drop(_1) -> [return: bb21, unwind: bb22]; // bb35[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb36: {                              // cleanup
        drop(_1) -> bb22;                // bb36[0]: scope 0 at test.rs:31:1: 31:2
    }

    bb37: {                             
        _13 = discriminant(_1);          // bb37[0]: scope 0 at test.rs:31:1: 31:2
        switchInt(move _13) -> [1isize: bb31, otherwise: bb35]; // bb37[1]: scope 0 at test.rs:31:1: 31:2
    }

    bb38: {                              // cleanup
        _14 = discriminant(_1);          // bb38[0]: scope 0 at test.rs:31:1: 31:2
        switchInt(move _14) -> [1isize: bb23, otherwise: bb36]; // bb38[1]: scope 0 at test.rs:31:1: 31:2
    }
}

@glandium
Copy link
Contributor Author

I think the most relevant fact is this difference between MIR inlining being enabled or not:

  • with MIR inlining disabled, this basic block in MIR:
    bb5: {                              
        _8 = const false;                // bb5[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        _10 = const box_free(move _4) -> bb4; // bb5[1]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: unsafe fn(*mut Foo<usize>) {box_free::<Foo<usize>>}
                                         // + val: Value(ByVal(Undef))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: unsafe fn(*mut Foo<usize>) {box_free::<Foo<usize>>}
                                         // + literal: const box_free
    }

becomes the following IR:

; <label>:22:                                     ; preds = %24
  store i8 0, i8* %3, align 1
  %23 = load i64*, i64** %4, align 8
  call void @_ZN4test8box_free17hbd5ff355ce749de2E(i64* %23)
  br label %18
  • with MIR inlining enabled, this basic block in MIR:
    bb5: {                              
        _8 = const false;                // bb5[0]: scope 0 at test.rs:29:5: 29:6
                                         // ty::Const
                                         // + ty: bool
                                         // + val: Value(ByVal(Bytes(0)))
                                         // mir::Constant
                                         // + span: test.rs:29:5: 29:6
                                         // + ty: bool
                                         // + literal: const false
        _12 = &mut (*_4);                // bb5[1]: scope 0 at test.rs:29:5: 29:6
        _13 = move _12 as *mut Foo<usize> (Misc); // bb5[2]: scope 0 at test.rs:29:5: 29:6
        _10 = const dealloc(move _13) -> bb4; // bb5[3]: scope 4 at test.rs:16:5: 16:17
                                         // ty::Const
                                         // + ty: fn(*mut Foo<usize>) {dealloc::<Foo<usize>>}
                                         // + val: Value(ByVal(Undef))
                                         // mir::Constant
                                         // + span: test.rs:16:5: 16:12
                                         // + ty: fn(*mut Foo<usize>) {dealloc::<Foo<usize>>}
                                         // + literal: const dealloc
    }

becomes

; <label>:20:                                     ; preds = %21
  store i8 0, i8* %3, align 1
  call void @_ZN4test7dealloc17hb146efc385cf7afbE(i64* %14)
  br label %16

whiich is weird... where did the extra code go?

@glandium
Copy link
Contributor Author

glandium commented Apr 18, 2018

The librustc_trans/mir changes from #48300 fix this issue.

bors added a commit that referenced this issue Apr 19, 2018
rustc_trans: also check dominators for SSA values in mir::analyze

Fixes #50041
nagisa added a commit to nagisa/rust that referenced this issue Jan 15, 2021
AFAICT the test case never landed alongside the fix for the issue.
m-ou-se added a commit to m-ou-se/rust that referenced this issue Jan 16, 2021
…ark-Simulacrum

Add a regression test for rust-lang#50041

AFAICT the test case never landed alongside the fix for the issue.
m-ou-se added a commit to m-ou-se/rust that referenced this issue Jan 16, 2021
…ark-Simulacrum

Add a regression test for rust-lang#50041

AFAICT the test case never landed alongside the fix for the issue.
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 16, 2021
Rollup of 17 pull requests

Successful merges:

 - rust-lang#78455 (Introduce {Ref, RefMut}::try_map for optional projections in RefCell)
 - rust-lang#80144 (Remove giant badge in README)
 - rust-lang#80614 (Explain why borrows can't be held across yield point in async blocks)
 - rust-lang#80670 (TrustedRandomAaccess specialization composes incorrectly for nested iter::Zips)
 - rust-lang#80681 (Clarify what the effects of a 'logic error' are)
 - rust-lang#80764 (Re-stabilize Weak::as_ptr and friends for unsized T)
 - rust-lang#80901 (Make `x.py --color always` apply to logging too)
 - rust-lang#80902 (Add a regression test for rust-lang#76281)
 - rust-lang#80941 (Do not suggest invalid code in pattern with loop)
 - rust-lang#80968 (Stabilize the poll_map feature)
 - rust-lang#80971 (Put all feature gate tests under `feature-gates/`)
 - rust-lang#81021 (Remove doctree::Import)
 - rust-lang#81040 (doctest: Reset errors before dropping the parse session)
 - rust-lang#81060 (Add a regression test for rust-lang#50041)
 - rust-lang#81065 (codegen_cranelift: Fix redundant semicolon warn)
 - rust-lang#81069 (Add sample code for Rc::new_cyclic)
 - rust-lang#81081 (Add test for rust-lang#34792)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant