Skip to content

MIR inlining leads to LLVM error around box_free #50041

Closed

Description

@glandium

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.

Activity

  1. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

    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}
    
  2. changed the title [-]MIT inlining leads to LLVM error around box_free[/-] [+]MIR inlining leads to LLVM error around box_free[/+] on Apr 18, 2018
  3. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

    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.

  4. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

    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
        }
    }
    
  5. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

    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.

  6. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

    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
        }
    }
    
  7. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

    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?

  8. glandium commented on Apr 18, 2018

    @glandium
    ContributorAuthor

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

  9. added a commit that references this issue on Apr 19, 2018
    5dc896e
  10. added a commit that references this issue on Jan 16, 2021
  11. added a commit that references this issue on Jan 16, 2021
  12. added a commit that references this issue on Jan 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions