I've prepared a patch and test to add alignas and alignof support to
the ecb library. This is "ecb-alignas0.patch", attached to this mail.
While making this patch, I found out a lot about strange behavior of
certain compilers, but probably not everything, so there may still be
problems.
I've made a test program "ecb_align_test.c" that can check some of the
behavior of the patch. After patching libecb.h, please compile and
run the test program with whatever compiler you have available, and
see if it works. I recommend that you try to compile it separately as
a C source and a C++ source, because the patch should work in both
cases, but the language and available features differ. I also
recommend that you build in both a C11 and C99 mode, and both a C++11
(or later) and C++98 mode, if your compiler has such an option. I
will test with msvc 2013 next week. The program should compile, and
when ran, print "Alignas test ok." after some other debug information.
If you get a failure, please report on the mailing list, possibly with
a patch.
Some notes about the implementation.
1. I do not check for the version of gcc, because even on a new enough
version there seems to be no way to use alignas or _Alignas in C99 or
C++98 mode.
2. Msvc gives an error to a declaration like __declspec(align(1))
__declspec(align(64)) which is why I insist on no doubled
ecb_alignas(v).
3. Clang gives a syntax error to a declaration like
__attribute__((unused)) alignas(64) char x; which is why the
documentation insists that ecb_alignas(v) much come before ecb_unused.
4. I don't allow putting the ecb_alignas(v) after a variable name,
because MSC gives a syntax error to a declaration like int x
__declspec(align(64));
5. I haven't tried more exotic compilers, or old versions of
compilers, at all. It's likely that there will be failures on some
compilers other than gcc, clang, msc.
Ambrus
diff -u libecb/ecb.h libecb/ecb.h
--- libecb/ecb.h 2015-09-04 22:30:16.224005569 +0200
+++ libecb/ecb.h 2015-09-05 00:12:35.956005612 +0200
@@ -399,6 +399,26 @@
#define ecb_cold
#endif
+#if 201103L <= __cplusplus || 201112L <= __STDC_VERSION__
+#include <stdalign.h>
+ #define ecb_alignas(align_size) alignas(align_size)
+ #define ecb_alignof(atype) alignof(atype)
+ #define ECB_ALIGNASBACKEND 3
+#elif __GNUC__
+ #define ecb_alignas(align_size) __attribute__((aligned(align_size)))
+ #define ecb_alignof(atype) __alignof__(atype)
+ #define ECB_ALIGNASBACKEND 1
+#elif _MSC_VER
+ #define ecb_alignas_weak(align_size) __declspec(align(align_size))
+ #define ecb_alignof(atype) __alignof(atype)
+ #define ECB_ALIGNASBACKEND 2
+#else
+ /* No suitable alignas and alignof replacement found. */
+#endif
+#ifdef ecb_alignas
+ #define ecb_alignas_weak(align_size) ecb_alignas(align_size)
+#endif
+
/* put around conditional expressions if you are very sure that the */
/* expression is mostly true or mostly false. note that these return */
/* booleans, not the expression. */
diff -u libecb/ecb.pod libecb/ecb.pod
--- libecb/ecb.pod 2015-09-04 22:30:16.224005569 +0200
+++ libecb/ecb.pod 2015-09-05 00:30:50.380005824 +0200
@@ -398,6 +398,45 @@
}
};
+=item ecb_alignas(align_size)
+
+Marks an object to be overaligned, aligned to a multiple of align_size bytes.
+
+For a variable (which could be global, static, local, or an object member
+of a structure), put this macro call at the very beginning of the
+definition of that variable. In C++ only, you can also increase the
+required alignment of a newly defined structure type, by putting the macro
+call between the struct or class keyword and the structure tag name.
+You must use at most one call of this macro in any definition.
+The macro call must precede attributes like ecb_unused.
+(If you use the macro in any other way, your code may break in some
+compiler environments, even silently.) The parameter alignas_size must be
+an integer (in particular, it must not be a type), and a power of two.
+If the alignment is too big (depending on the compiler, linker, and
+dynamic linker), this may be ignored. You should not give an alignment
+lower than the usual alignment of object. If you do, you may or may not
+get an error.
+
+If the complier does not support this feature, the macro will not be defined.
+
+=item ecb_alignas_weak(align_size)
+
+Same as ecb_alignas, except the compiler may not align the object
+when it is allocated on the stack (as a local variable).
+
+Examples:
+
+ ecb_alignas_weak(64) static const char c0[64] = {0};
+ extern const char c1[64];
+ ecb_alignas_weak(64) const char c1[64] = {0};
+ struct d2 { ecb_alignas_weak(64) char c2[64]; };
+ #ifdef __cplusplus
+ struct d3;
+ struct ecb_alignas_weak(64) d3 { char c3[64]; };
+ struct d4 { static char c4[64]; };
+ ecb_alignas_weak(64) char d4::c4[64] = {0};
+ #endif
+
=back
=head2 OPTIMISATION HINTS
@@ -810,6 +849,12 @@
for (i = 0; i < ecb_array_length (primes); i++)
sum += primes [i];
+=item ecb_alignof(atype)
+
+Queries the alignment requirement of a type. The parameter must be
+an object type or reference type. The macro call expands to a constexpr
+integer expression, giving the alignment requirement in bytes.
+
=back
=head2 SYMBOLS GOVERNING COMPILATION OF ECB.H ITSELF
/*! \file calign_test.cpp */
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include "ecb.h"
#ifdef __cplusplus
namespace {
#endif
#ifndef ecb_alignas_weak
#error ecb_alignas_weak not available for testing
#endif
#ifndef ecb_alignof
#error ecb_alignof not available for testing
#endif
ecb_alignas_weak(64) static const char c0[64] = {0};
extern const char c1[64];
ecb_alignas_weak(64) const char c1[64] = {0};
#ifdef __cplusplus
struct d4 { static char c4[64]; };
ecb_alignas_weak(64) ecb_unused char d4::c4[64] = {0};
#endif
struct d5 { char z5; char c5[64]; };
#ifdef __cplusplus
struct d3;
struct ecb_alignas_weak(64) d3 { char z3; char c3[64]; };
struct d6 { char z6; struct d3 c6; };
#endif
struct d2 { char z2; ecb_alignas_weak(64) char c2[64]; };
struct d7 { char z7; struct d2 c7; };
#define XASSERT(cond, dbg) \
{ enum { dbg##_j = !!(cond), }; \
ecb_unused char dbg##_g[dbg##_j ? 1 : -1] = {0}; \
if (!(dbg##_j)) { abort(); } }
#define ACHECK(stag, field, wsize, walign, woffset) \
XASSERT(wsize == sizeof(struct stag), stag##_size) \
XASSERT(walign == ecb_alignof(struct stag), stag##_align) \
XASSERT(woffset == offsetof(struct stag, field), stag##_offset)
int
caligntest_main()
{
ACHECK(d5, c5, 1+64, 1, 1)
#ifdef __cplusplus
ACHECK(d3, c3, 2*64, 64, 1)
ACHECK(d6, c6, 3*64, 64, 64)
XASSERT(64 == ecb_alignof(d7 &), d7ref_align)
#endif
ACHECK(d2, c2, 2*64, 64, 64)
ACHECK(d7, c7, 3*64, 64, 64)
printf("Features: ");
#ifdef __cplusplus
printf("c++ %ld ", (long)(__cplusplus+0));
#endif
#ifdef __STDC_VERSION__
printf("stdc %ld ", (long)(__STDC_VERSION__));
#endif
#ifdef __GNUC__
printf("gnuc %ld.%ld ", (long)(__GNUC__), (long)(__GNUC_MINOR__));
#endif
#ifdef _MSC_VER
printf("msc %ld ", (long)(_MSC_VER));
#endif
ecb_alignas_weak(64) char okmsg[] = "Alignas test ok.\n";
printf("; alignas backend id %d.\n%s", (int)ECB_ALIGNASBACKEND, okmsg);
return 0;
}
#ifdef __cplusplus
}
#endif
int
main()
{
return caligntest_main();
}
/* END */
_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/mailman/listinfo/libev