Boost logo

Boost :

From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2021-01-26 08:53:04


On 25/01/2021 23:08, Gavin Lambert via Boost wrote:
> On 26/01/2021 10:53 am, Edward Diener wrote:
>> Please name the Boost low level libraries which have specific code
>> aimed at the platform/architecture combination. I am not talking about
>> code for just Mac or Linux or Solaris or Windows but code that
>> actually does something different when run on Intel or ARM or AArch64
>> etc. I still imagine that if such Boost libraries exist there are
>> still very, very few Boost libraries with dependence on such code. I
>> am not arguing that testing on non-Intel is in any way wrong but
>> simply that very, very few libraries should be impacted by different
>> architectures in any way.
>
> Boost.Atomic (and consequently Boost.Lockfree too) is the obvious one
> (that Niall already hinted at), but parts of Boost.Thread also apply.
>
> Add to that list other low-level libraries such as Boost.Endian,
> Boost.Coroutine[2], and Boost.Fiber as well.
>
> There are also some surprise gotchas in other libraries that do their
> own spinlocks or pointer-packing, such as Boost.SmartPtr and likely others.
>
> Meanwhile other libraries like Boost.Serialization (and consumers of
> same) also make their own assumptions about things like endianness and
> type structure, which may not matter too much in isolation but becomes
> very important if you're intending to use it as a portable network or
> disk format.

There are even more subtle problems than that.

Consider this bit of code I encountered recently. This was a trivially
copyable struct whose contents were initialised at construction to all
bits one by as if memset(this, 0xff, sizeof(T)). The struct's members
were set, or not set, by code depending on what happens at runtime. If a
member was set by code, its value would not be all bits one.

The logical code to write therefore was this:

// All bits one representation is a negative NaN under IEEE 754
static constexpr float FLOAT_UNSET = -__builtin_nanf("0xffffff");

struct Foo
{
  float x{FLOAT_UNSET};

  constexpr Foo() {} // this is constexpr
};

...

if(foo.x == FLOAT_UNSET) ...

The above code works absolutely fine if, and only if your compiler is
x86/x64/ARMv8 and the target is x86/x64/ARMv8. If your compiler, OR your
target, is ARMv7, all bets are off.

Why? Because ARMv7 doesn't fully implement NaN. So, if the compiler were
x64/ARMv8 and the target were ARMv7, IF the compiler executes the code
consteval, you get all bits one float, but if instead it executes the
code at runtime, you get some other NaN float. This is because consteval
executed expressions by definition are what the compiler itself
experiences, which may be quite different to what the target
architecture experiences.

Subtle stuff like the above causes all sorts of fun in the real world.
x64 is extremely benign and tolerant compared to ARMv7, which is
probably bigger in terms of total code execution space nowadays. So,
restating what I said earlier, I think good engineering means you ensure
your C++ works well on ARMv7, and if it works well there, you have an
excellent chance of it working well on x64 and ARMv8. The reverse is not
true.

And incidentally ARMv7 will be a huge chunk of market share for decades
to come. Most of the mid low end microcontrollers are ARMv7, they likely
will continue to displace PIC and AVR CPUs. Those didn't run C++ well,
so we never really experienced much of our userbase trying to say run
Boost on them. However all ARMv7 CPUs run C++ very well, so it would be
a great surprise if more copies of Boost don't start getting shipped on
billions of lower end embedded systems in the coming decade.

Niall


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk