Stream: t-compiler

Topic: const-eval-enums-niche-optimizations


oli (Jan 08 2019 at 11:33, on Zulip):

I am trying to figure out a recent memory usage regression and for that I had a look at how much memory constants are using. Something seems like it's not adding up. I created a small playground example that shows my problem: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=de695b292b3e1d6f21043293c76c2996

oli (Jan 08 2019 at 11:34, on Zulip):

The Scalar enum is 24 bytes in size (a u128 (16 bytes) a u8 (1 byte) and a discriminant (1 byte)). The missing 6 bytes are padding

oli (Jan 08 2019 at 11:34, on Zulip):

So far so good, I can live with that

oli (Jan 08 2019 at 11:35, on Zulip):

But then ConstValue takes up 56 bytes, even though I would have assumed the two Scalars to add up to 48 and the discriminant of ConstValue would end up in the Scalar's padding

oli (Jan 08 2019 at 11:35, on Zulip):

or can't we use that padding because writing to one of the scalars would overwrite the padding (and thus nuke the discriminant)?

nagisa (Jan 08 2019 at 11:46, on Zulip):

Contents of padding in a type are undefined

nagisa (Jan 08 2019 at 11:46, on Zulip):

so while it would be possible to use "padding" that belonged to the containing type (i.e. (Scalar, Scalar)), it is not possible to use Scalar’s own padding for this.

oli (Jan 08 2019 at 11:47, on Zulip):

so... If I added an enum Foo { Bar = 0 } field to the type I could overwrite that assumption and niche opts could fill in the field with other values to encode the discriminant?

nagisa (Jan 08 2019 at 11:49, on Zulip):

Maybe I explained it unwell… The niche finding optimisation should not and cannot, I believe, operate recursively. I.e. regardless of what padding Scalar has, niche filling a (Scalar, Scalar) sees a tuple of two opaque 24-byte blobs… I believe…

oli (Jan 08 2019 at 11:49, on Zulip):

oh

nagisa (Jan 08 2019 at 11:50, on Zulip):

A good reason, as you intuited, would be somebody overwriting the padding of one of the Scalars in case a reference was taken to it and assigned through that.

oli (Jan 08 2019 at 11:52, on Zulip):

still. If I filled the padding with a known enum like bool, I get another 254 values to assign to that field for encoding that another variant is in use here

nagisa (Jan 08 2019 at 11:54, on Zulip):

If you changed Scalar itself, sure.

nagisa (Jan 08 2019 at 11:54, on Zulip):

actually

nagisa (Jan 08 2019 at 11:54, on Zulip):

hmm

nagisa (Jan 08 2019 at 11:54, on Zulip):

bool is represented as a byte in memory with two valid values

nagisa (Jan 08 2019 at 11:55, on Zulip):

&bool cannot be anything other than 1 or 0 when dereferenced, and if we were to "niche-fill" that, it would be expensive af

nagisa (Jan 08 2019 at 11:56, on Zulip):

because every use of bool would have to mask for the single bit

oli (Jan 08 2019 at 11:56, on Zulip):

my turn in having explained badly

nagisa (Jan 08 2019 at 11:57, on Zulip):

But perhaps something like #[compiler_builtin] struct ByteSizedNiche; would work?

oli (Jan 08 2019 at 11:57, on Zulip):

I don't want niche optimizations to write anything but 0 and 1 to the bool field as long as we are in the variant that has that bool

oli (Jan 08 2019 at 11:57, on Zulip):

Other variants who only have padding here can use the field for encoding their discriminant

oli (Jan 08 2019 at 11:58, on Zulip):

as long as all variants have padding here

nagisa (Jan 08 2019 at 11:58, on Zulip):

@Oli sure.

nagisa (Jan 08 2019 at 11:59, on Zulip):

but then you have 2 discriminant values for a single variant?

oli (Jan 08 2019 at 11:59, on Zulip):

oh

oli (Jan 08 2019 at 11:59, on Zulip):

well I wanted enum Foo { Bar = 0 } anyway

nagisa (Jan 08 2019 at 11:59, on Zulip):

which does not sound so much of a problem until you get to things like std::mem::discriminant_value().

nagisa (Jan 08 2019 at 12:01, on Zulip):

yaeh idk, the current optimisation is definitely more conservative than it needs to be at times.

oli (Jan 08 2019 at 12:01, on Zulip):

Result<&'static u32, Foo> is 8 bytes, so we are doing this correctly already :confused:

nagisa (Jan 08 2019 at 12:02, on Zulip):

What is Foo here?

oli (Jan 08 2019 at 12:02, on Zulip):

enum Foo { Bar = 0 }

oli (Jan 08 2019 at 12:02, on Zulip):

oh

oli (Jan 08 2019 at 12:03, on Zulip):

doesn't work with #[repr(u64)]

oli (Jan 08 2019 at 12:03, on Zulip):

it only worked as a ZST

oli (Jan 08 2019 at 12:03, on Zulip):

that explains it

oli (Jan 08 2019 at 12:03, on Zulip):

we're just not doing this optimization :D

Jake Goulding (Jan 08 2019 at 18:04, on Zulip):

fix it; fix it; fix it

Last update: Nov 22 2019 at 04:30UTC