Remix.run Logo
krick 5 hours ago

That's very unpleasant to hear. It's sad to be reminded that Rust compiler is not magic and cannot just... do these things somehow. Sure, all abstractions do have some cost, but, man, 17% performance gain by virtue of replacing enum with this monstrosity? That's very annoying.

maplant 5 hours ago | parent | next [-]

It can't do these things because it's not wanted. Say you have the following:

  enum Value {
      Float(f64),
      Ptr(*const T),
  }
Do you want the compiler to disallow certain bit patterns in the Float variant simply so that it can implement NanBoxing?
vlovich123 4 hours ago | parent | next [-]

Probably with an annotation around a NanBoxable(f64) type that tells it to do that.

That being said, the optimization is complex that may be insufficient:

> For my boxing scheme, I picked a bias value such that the lowest two bits end up being 10. That 1 in bit index 1 indicates that doubles can't be directly compared for equality. Amazingly, we only lose two bits of exponent, and we keep the full precision of the mantissa, meaning we lose no significant digits in the flonum representation.

This suggests the optimization needs more information about specifically how you want to box the float. There probably is some primitives worth considering standardizing to make this kind of optimization possible so that the tunable parameters are passed as const generic values.

gpm 2 hours ago | parent | prev [-]

Or actually doing what they did here where it changes it to a

    enum Value {
         SimpleFloat(64bit value),
         ComplexNan(Heap pointer)
         Ptr(*const T)
    }
You lose out on performance if you use the bit patterns in the float that most people don't use very much, but you keep the correctness.

I'd be very unhappy if a compiler silently did this to me - it would make performance extremely hard to reason about. But it's not quite as bad as changing the semantics.

speedstyle 4 hours ago | parent | prev [-]

A 64-bit sum type can't magically combine an i64, f64, and several raw pointers, each of which carry a full 64 bits themselves. You have to change the semantics of the code. Some semantics could be expressed more easily with compiler improvements, allowing eg `Aligned<T>` like `NonNull<T>`, or `FiniteF64` like `NonZeroU64`, or even `#[range(0..1<<60)] u64`, but you still couldn't overlap two `Aligned`s in one enum, because only one can be stored unchanged, the others need masking off before usage. Even if the enum semantics allowed this, I'm not sure the compiler should do this kind of compute/memory tradeoff automagically. Which doesn't mean you can't write nice abstractions over it, there's a few tagged ptr crates which aim to do it for you