Stream: t-compiler

Topic: Why is this generator one byte bigger than expected?


bjorn3 (May 10 2020 at 17:10, on Zulip):

I expect the generator returned from overlap_x_and_y to be 1025 bytes. (1024 bytes for Foo + 1 byte for the discriminant) When compiling using cg_clif this is indeed true. However when compiling using cg_llvm it gives 1026 bytes. This mismatch causes the size-moved-locals.rs test to fail for cg_clif.

// based on size-moved-locals.rs
#![feature(generators, generator_trait)]

use std::ops::Generator;

const FOO_SIZE: usize = 1024;
struct Foo([u8; FOO_SIZE]);

impl Drop for Foo {
    fn drop(&mut self) {}
}

fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let x = Foo([0; FOO_SIZE]);
        yield;
        drop(x);
        let y = Foo([0; FOO_SIZE]);
        yield;
        drop(y);
    }
}

fn main() {
    assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y()));
}
Matthew Jasper (May 10 2020 at 17:19, on Zulip):

The extra byte looks to be a drop flag

Matthew Jasper (May 10 2020 at 17:20, on Zulip):

I'm not sure why compiling for cg_clif would change this.

Jonas Schievink (May 10 2020 at 17:21, on Zulip):

Why do we still have drop flags anywhere?

Jonas Schievink (May 10 2020 at 17:22, on Zulip):

Oh, across a yield

Jonas Schievink (May 10 2020 at 17:22, on Zulip):

But there are no dynamic drops in that generator

bjorn3 (May 10 2020 at 17:23, on Zulip):

Layout of the generator:

error: layout_of([static generator@src/main.rs:16:5: 23:6 {Foo, ()}]) = Layout {
    fields: Arbitrary {
        offsets: [
            Size {
                raw: 0,
            },
        ],
        memory_index: [
            0,
        ],
    },
    variants: Multiple {
        discr: Scalar {
            value: Int(
                I8,
                false,
            ),
            valid_range: 0..=4,
        },
        discr_kind: Tag,
        discr_index: 0,
        variants: [
            Layout {
                fields: Arbitrary {
                    offsets: [],
                    memory_index: [],
                },
                variants: Single {
                    index: 0,
                },
                abi: Aggregate {
                    sized: true,
                },
                largest_niche: None,
                align: AbiAndPrefAlign {
                    abi: Align {
                        pow2: 0,
                    },
                    pref: Align {
                        pow2: 3,
                    },
                },
                size: Size {
                    raw: 2,
                },
            },
            Layout {
                fields: Arbitrary {
                    offsets: [],
                    memory_index: [],
                },
                variants: Single {
                    index: 1,
                },
                abi: Aggregate {
                    sized: true,
                },
                largest_niche: None,
                align: AbiAndPrefAlign {
                    abi: Align {
                        pow2: 0,
                    },
                    pref: Align {
                        pow2: 3,
                    },
                },
                size: Size {
                    raw: 2,
                },
            },
            Layout {
                fields: Arbitrary {
                    offsets: [],
                    memory_index: [],
                },
                variants: Single {
                    index: 2,
                },
                abi: Aggregate {
                    sized: true,
                },
                largest_niche: None,
                align: AbiAndPrefAlign {
                    abi: Align {
                        pow2: 0,
                    },
                    pref: Align {
                        pow2: 3,
                    },
                },
                size: Size {
                    raw: 2,
                },
            },
            Layout {
                fields: Arbitrary {
                    offsets: [
                        Size {
                            raw: 2,
                        },
                        Size {
                            raw: 1,
                        },
                    ],
                    memory_index: [
                        1,
                        0,
                    ],
                },
                variants: Single {
                    index: 3,
                },
                abi: Aggregate {
                    sized: true,
                },
                largest_niche: None,
                align: AbiAndPrefAlign {
                    abi: Align {
                        pow2: 0,
                    },
                    pref: Align {
                        pow2: 3,
                    },
                },
                size: Size {
                    raw: 1026,
                },
            },
            Layout {
                fields: Arbitrary {
                    offsets: [
                        Size {
                            raw: 2,
                        },
                        Size {
                            raw: 1,
                        },
                    ],
                    memory_index: [
                        1,
                        0,
                    ],
                },
                variants: Single {
                    index: 4,
                },
                abi: Aggregate {
                    sized: true,
                },
                largest_niche: None,
                align: AbiAndPrefAlign {
                    abi: Align {
                        pow2: 0,
                    },
                    pref: Align {
                        pow2: 3,
                    },
                },
                size: Size {
                    raw: 1026,
                },
            },
        ],
    },
    abi: Aggregate {
        sized: true,
    },
    largest_niche: Some(
        Niche {
            offset: Size {
                raw: 0,
            },
            scalar: Scalar {
                value: Int(
                    I8,
                    false,
                ),
                valid_range: 0..=4,
            },
        },
    ),
    align: AbiAndPrefAlign {
        abi: Align {
            pow2: 0,
        },
        pref: Align {
            pow2: 3,
        },
    },
    size: Size {
        raw: 1026,
    },
}
bjorn3 (May 10 2020 at 17:25, on Zulip):

MIR of the generator:

fn overlap_x_and_y::{{closure}}#0(_1: std::pin::Pin<&mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}]>, _2: ()) -> std::ops::GeneratorState<(), ()> {
    let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at src/main.rs:16:5: 23:6
    let mut _3: [u8; _];                 // in scope 0 at src/main.rs:17:21: 17:34
    let mut _4: ();                      // in scope 0 at src/main.rs:18:9: 18:14
    let _5: ();                          // in scope 0 at src/main.rs:19:9: 19:16
    let mut _6: Foo;                     // in scope 0 at src/main.rs:19:14: 19:15
    let mut _7: [u8; _];                 // in scope 0 at src/main.rs:20:21: 20:34
    let mut _8: ();                      // in scope 0 at src/main.rs:21:9: 21:14
    let _9: ();                          // in scope 0 at src/main.rs:22:9: 22:16
    let mut _10: Foo;                    // in scope 0 at src/main.rs:22:14: 22:15
    let mut _11: ();                     // in scope 0 at src/main.rs:16:15: 16:15
    let mut _12: isize;                  // in scope 0 at src/main.rs:16:5: 23:6
    scope 1 {
        debug x => (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).0: Foo); // in scope 1 at src/main.rs:17:13: 17:14
        scope 2 {
            debug y => (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#4).0: Foo); // in scope 2 at src/main.rs:20:13: 20:14
        }
    }

    bb0: {
        _12 = discriminant((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}]))); // scope 0 at src/main.rs:16:5: 23:6
        switchInt(move _12) -> [0u32: bb1, 1u32: bb10, 2u32: bb9, 3u32: bb7, 4u32: bb8, otherwise: bb11]; // scope 0 at src/main.rs:16:5: 23:6
    }

    bb1: {
        (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).1: bool) = const false; // scope 0 at src/main.rs:17:13: 17:14
        StorageLive(_3);                 // scope 0 at src/main.rs:17:21: 17:34
        _3 = [const 0u8; FOO_SIZE];      // scope 0 at src/main.rs:17:21: 17:34
        (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).1: bool) = const true; // scope 0 at src/main.rs:17:17: 17:35
        ((((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).0: Foo).0: [u8; _]) = move _3; // scope 0 at src/main.rs:17:17: 17:35
        StorageDead(_3);                 // scope 0 at src/main.rs:17:34: 17:35
        StorageLive(_4);                 // scope 1 at src/main.rs:18:9: 18:14
        ((_0 as Yielded).0: ()) = move _4; // scope 1 at src/main.rs:18:9: 18:14
        discriminant(_0) = 0;            // scope 1 at src/main.rs:18:9: 18:14
        discriminant((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}]))) = 3; // scope 1 at src/main.rs:18:9: 18:14
        return;                          // scope 1 at src/main.rs:18:9: 18:14
    }

    bb2: {
        StorageDead(_6);                 // scope 1 at src/main.rs:19:15: 19:16
        StorageDead(_5);                 // scope 1 at src/main.rs:19:16: 19:17
        StorageLive(_7);                 // scope 1 at src/main.rs:20:21: 20:34
        _7 = [const 0u8; FOO_SIZE];      // scope 1 at src/main.rs:20:21: 20:34
        ((((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#4).0: Foo).0: [u8; _]) = move _7; // scope 1 at src/main.rs:20:17: 20:35
        StorageDead(_7);                 // scope 1 at src/main.rs:20:34: 20:35
        StorageLive(_8);                 // scope 2 at src/main.rs:21:9: 21:14
        ((_0 as Yielded).0: ()) = move _8; // scope 2 at src/main.rs:21:9: 21:14
        discriminant(_0) = 0;            // scope 2 at src/main.rs:21:9: 21:14
        discriminant((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}]))) = 4; // scope 2 at src/main.rs:21:9: 21:14
        return;                          // scope 2 at src/main.rs:21:9: 21:14
    }

    bb3 (cleanup): {
        (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).1: bool) = const false; // scope 0 at src/main.rs:23:5: 23:6
        discriminant((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}]))) = 2; // scope 0 at src/main.rs:16:5: 23:6
        resume;                          // scope 0 at src/main.rs:16:5: 23:6
    }

    bb4 (cleanup): {
        StorageDead(_6);                 // scope 1 at src/main.rs:19:15: 19:16
        StorageDead(_5);                 // scope 1 at src/main.rs:19:16: 19:17
        goto -> bb3;                     // scope 1 at src/main.rs:1:1: 1:1
    }

    bb5: {
        StorageDead(_10);                // scope 2 at src/main.rs:22:15: 22:16
        StorageDead(_9);                 // scope 2 at src/main.rs:22:16: 22:17
        _11 = const ();                  // scope 0 at src/main.rs:16:15: 23:6
        (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).1: bool) = const false; // scope 0 at src/main.rs:23:5: 23:6
        ((_0 as Complete).0: ()) = move _11; // scope 0 at src/main.rs:23:6: 23:6
        discriminant(_0) = 1;            // scope 0 at src/main.rs:23:6: 23:6
        discriminant((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}]))) = 1; // scope 0 at src/main.rs:23:6: 23:6
        return;                          // scope 0 at src/main.rs:23:6: 23:6
    }

    bb6 (cleanup): {
        StorageDead(_10);                // scope 2 at src/main.rs:22:15: 22:16
        StorageDead(_9);                 // scope 2 at src/main.rs:22:16: 22:17
        goto -> bb3;                     // scope 1 at src/main.rs:1:1: 1:1
    }

    bb7: {
        StorageLive(_4);                 // scope 0 at src/main.rs:16:5: 23:6
        StorageDead(_4);                 // scope 1 at src/main.rs:18:13: 18:14
        StorageLive(_5);                 // scope 1 at src/main.rs:19:9: 19:16
        StorageLive(_6);                 // scope 1 at src/main.rs:19:14: 19:15
        (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).1: bool) = const false; // scope 1 at src/main.rs:19:14: 19:15
        _6 = move (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).0: Foo); // scope 1 at src/main.rs:19:14: 19:15
        _5 = const std::mem::drop::<Foo>(move _6) -> [return: bb2, unwind: bb4]; // scope 1 at src/main.rs:19:9: 19:16
    }

    bb8: {
        StorageLive(_8);                 // scope 0 at src/main.rs:16:5: 23:6
        StorageDead(_8);                 // scope 2 at src/main.rs:21:13: 21:14
        StorageLive(_9);                 // scope 2 at src/main.rs:22:9: 22:16
        StorageLive(_10);                // scope 2 at src/main.rs:22:14: 22:15
        _10 = move (((*(_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#4).0: Foo); // scope 2 at src/main.rs:22:14: 22:15
        _9 = const std::mem::drop::<Foo>(move _10) -> [return: bb5, unwind: bb6]; // scope 2 at src/main.rs:22:9: 22:16
    }

    bb9: {
        assert(const false, "generator resumed after panicking") -> bb9; // scope 0 at src/main.rs:16:5: 23:6
    }

    bb10: {
        assert(const false, "generator resumed after completion") -> bb10; // scope 0 at src/main.rs:16:5: 23:6
    }

    bb11: {
        unreachable;                     // scope 0 at src/main.rs:16:5: 23:6
    }
}
bjorn3 (May 10 2020 at 17:26, on Zulip):

I don't see any drop flags

Matthew Jasper (May 10 2020 at 17:31, on Zulip):

_1.0: &mut [static generator@src/main.rs:16:5: 23:6 {Foo, ()}])) as variant#3).1 is the drop flag

bjorn3 (May 10 2020 at 17:33, on Zulip):

Ah

bjorn3 (May 10 2020 at 17:40, on Zulip):

Found the difference between cg_llvm and cg_clif! Because cg_clif doesn't yet support unwinding, I was passing -Cpanic=abort by default. Using -Cpanic=unwind fixed the size difference.

Last update: May 29 2020 at 18:05UTC