Libecb: notes about alignas and alignof

Marc Lehmann schmorp at schmorp.de
Sun Aug 9 15:42:37 CEST 2015


On Sat, Aug 08, 2015 at 06:05:10PM +0200, Zsb√°n Ambrus <ambrus at math.bme.hu> wrote:
> I'd really like a portable way to use alignof and alignas.  This seems
> impossible, especially on old compilers, but I still think libecb
> might still try to help in some cases.  I don't know the final
> solution of what could be done, so here I'm trying to collect
> information about what compilers support what features, and how you
> can test them without a configure system.  I'll take alignof and
> alignas separately.  These are mostly symmetric, but have differences.

One thing I thought about, how useful would it be to have two alignas macros:

   alignas_required
   alignas_besteffort

(these are not the proposed names) - the required one would only exist when
available, while the besteffort one would always exist, but not guarantee
alignment.

Something similar could be done with alignof, where one macro would be
exact or undefined, and the other might guess or simply use sizeof(long)
or something like that.

> 5. The std::alignment_of template in <type_traits> would be a suitable
> replacement to alignof, but it's probably only available in C++11
> compilers that have alignof anyway.

(agreed)

> 7. The boost config module has some macros like BOOST_NO_CXX11_ALIGNAS
> that try to tell whether compilers have C++11 alignas, but it's hard
> to read the boost source code to find out how this works, and it's
> sometimes not precise, so it's useful only as a starting point.

that's my experience with boost, too, but in the end, all these libraries
only cook with water and have to adjust continously.

> The alignas specifier is more complicated because it can syntactically
> appear in multiple places in the code (qualifying a struct or an
> object declaration), and only some of these could be possible on
> certain compilers, and also because it can take both a type or a value
> as its parameter.  Let me talk about these separately now.

It might be possible to split these into alignas_type or alignas_object or
sth. similar.

> 2. The _Alignas keyword, and the macro alignas in <stdalign.h>, is
> available in C11, and I don't know the compiler versions.

It would be super useful to be able to check for the existance of headers
indeed, and with clang and gcc it's possible at least. We have thought
about this for a while, but so far came to the conclusion that testing
compiler headers is not generally useful enough (on compilers that have it
we usually have other means).

> 4. There's an MS complier attribute __declspec(align()).  I think this
> doesn't quite support the full semantics of alignof, but can still
> help in some cases.  The MSDN documentation at

If we can identify a common subset, maybe its worth only supporting the
common subset? For example, I wouldn't be surprised if many compilers had
somewhat low limits on how much you cna align objects.

> alignment, in particular, it sometimes doesn't align objects on the
> stack, which could be why they don't want to add the alignas keyword.

Many older gcc versions don't align objects on the stack. It's not
atcually trivial to do.

> 5. The std::aligned_storage template class lets you create overaligned
> types in some special cases and with ugly syntax.  However, it is
> probably available only in C++11 compilers that have alignas anyway,
> so it won't help much.

yup.

> 6. Boost has an implementation of aligned_storage somewhere in the
> TypeTraits module, which could give some hints.

as usual, yes.

> The syntax of where you can place these in a declaration is picky, and
> differ for these.  For a struct definition, put alignas(32) or
> __attribute__((aligned(32))) or __declspec(align(32)) between the
> struct keyword and the name of the newly defined structure type.  For
> a variable (member) definition, put alignas(32) or
> __attribute((aligned(32))) or __declspec(align(32)) at the very
> beginning of the declaration.  Placing them like these is at least
> accepted without a warning on some compilers, but it's hard to be sure
> it actually set alignment.

The solution would be to split the macro in as many parts as needed,

   declare_aligned_struct(name,body)

Or somesuch. But I feel it is getting messy.

> Sometimes I'd like an aligned_alloc function (as in C11).  Most C
> libraries, even the oldest ones, seem to have something like this, but
> with lots of differences in the interface.  Boost has an
> implementation which seems to work, but I think it doesn't always do
> the optimal thing.  This, however, probably does not belong to libecb.

One of the original plans was to feature a mode where you could seperately
compile header and implementation, to split big functions away. This could
go there, but indeed, it seems a bit misplaced and more suited for utility
libraries.

> Slightly related is reading and writing unaligned integers in the
> memory (and possibly floats too).  Boost now has a library that I can
> use for this (called Endian), which supports unaligned integers of all
> sizes and endiannesses, with a C++ interface.

Related, but very different, in that we can always support this
functionality, and we can cover a lot of ground with relatively little
effort.

Specifically, what I mean is read/write_u16/32/64 - do you have larger
types in mind, or more generic ones?

Frankly, after reading your analysis, I got the impression that
alignas/alignof is a gigantic task (while unaligned read/writes are
comparatively trivial).

> cpu types, and compilers don't seem to have an interface to do
> unaligned access, even though I think they should.  I've used this
> library to read a misaligned int64_t recently, but that didn't require
> any sort of performance.  Anyway, if you can figure out how to handle

If I get you right your concern would be that:

   *(uint64_t *)p

could be implemented with some instruction that requires strict
alignment? If not now, then in the future?

I haven't actually thought about that - if we have a read_u64 then the
compiler could potentially simd calls to this function after inlining it, or
worse.

We can either play risky then, or again resort to compiler builtins such
as (possibly) __builtin_assume_sligned or somesuch.

> this properly, some functions for this could still be useful for
> libecb.

And we cna always start with byte-wise read/writs.

-- 
                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_              http://www.deliantra.net
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      schmorp at schmorp.de
      -=====/_/_//_/\_,_/ /_/\_\



More information about the libev mailing list