Isn't it time there was a standard align statement?

A

artifact.one

It'd be really pleasant (in my opinion) if the next revision of the
C language actually allowed some portable control over data
alignment.

Compiler-specific mechanisms for this stuff are so varied that
it becomes impossible to even abstract the details away behind
preprocessor macros.

What I'd like to see:

/* per structure alignment */
align(16) struct xyz {
char x;
char y;
int z;
};

/* per member alignment (obviously padding before the first
member is illegal, so the entire structure would become aligned
in this case */
align(16) struct xyz {
align(16) char x;
char y;
int z;
};

/* per variable alignment */
align(16) unsigned int x;

I don't care about the syntax.

Now, obviously, C is meant to be implemented on everything from
self-aware weather-control mainframes, to motorized tie racks,
so in the case of the host implementation not supporting the specified
alignment, a warning should be emitted and either the closest or
natural alignment should be given. Warnings can obviously be made
fatal with compiler specific switches - and that's no business of the
language.

It just seems that this really should be standardized as it clearly
is useful for a vast number of programmers who need to get close to the
hardware but don't want to stray into assembly code (think Altivec,
SSE).
Sounds like EXACTLY the point of the C language, doesn't it?

I wouldn't mind so much if compiler implementors had come up with a
vaguely portable way of doing this, but they haven't even come close.
GCC and Intel have won joint first prize for 'most pleasant
implementation'
though (__attribute__ or _declspec()).

cheers,
MC
 
D

David T. Ashley

It'd be really pleasant (in my opinion) if the next revision of the
C language actually allowed some portable control over data
alignment.

It just seems that this really should be standardized as it clearly
is useful for a vast number of programmers who need to get close to the
hardware but don't want to stray into assembly code (think Altivec,
SSE).
Sounds like EXACTLY the point of the C language, doesn't it?

Your post is rather general and doesn't give a specific example of a
scenario where the current C mechanisms are inadequate.

Please don't make general criticisms of the language. Instead, post a
specific example of some effect or end-result you are trying to achieve and
why you believe you can't do it with the current mechanisms.

I've always found the current mechanisms to be adequate. Where alignment is
unknown or you need to do double-duty with a pointer, just define a variant
record and let the compiler figure it out ...
 
E

Eric Sosman

It'd be really pleasant (in my opinion) if the next revision of the
C language actually allowed some portable control over data
alignment.

Compiler-specific mechanisms for this stuff are so varied that
it becomes impossible to even abstract the details away behind
preprocessor macros.

What I'd like to see:

/* per structure alignment */
align(16) struct xyz {
char x;
char y;
int z;
};

Why would you "like to see" this? If you're dealing with
a particular compiler for a particular piece of hardware, you
can use whatever compiler-specific mechanisms are provided.
But if you're seeking "portable control," how portable is the
magic number 16?
> [...]
so in the case of the host implementation not supporting the specified
alignment, a warning should be emitted and either the closest or
natural alignment should be given. Warnings can obviously be made
fatal with compiler specific switches - and that's no business of the
language.

If different implementations can do whatever they please with
the directive, how "portable" is it? As with register you can
write it and be assured all compilers will accept it, but as with
register you don't really know what effect it will have on the code.
It just seems that this really should be standardized as it clearly
is useful for a vast number of programmers who need to get close to the
hardware but don't want to stray into assembly code (think Altivec,
SSE).

I'm not familiar with them, but I'll suppose they're machines
with unusual and finicky alignment constraints. Very well, then:
What *one* value can you put inside an align(N) directive such that
the data will be aligned as desired on both of these machines and
on all others, too? To put it another way, if you are concerned
about such details it seems "portability" has already ceased to be
a concern.
Sounds like EXACTLY the point of the C language, doesn't it?

You'll need to ask dmr, but I don't think so.
I wouldn't mind so much if compiler implementors had come up with a
vaguely portable way of doing this, but they haven't even come close.
GCC and Intel have won joint first prize for 'most pleasant
implementation'
though (__attribute__ or _declspec()).

The details of data alignment are themselves non-portable, so
the incentive to develop a portable means of controlling them seems
small. Whenever you decree that the alignment of thus-and-such
should be this-and-that, you immediately restrict the portability
of the code. All I can see is that you're proposing a portable
way to declare that a piece of code is non-portable.
 
C

CBFalconer

It'd be really pleasant (in my opinion) if the next revision of
the C language actually allowed some portable control over data
alignment.

Alignment is not for the benefit of the compiler, but to allow the
compiler to use the destination machine.
 
A

Ark

Eric said:
It'd be really pleasant (in my opinion) if the next revision of the
C language actually allowed some portable control over data
alignment.

Compiler-specific mechanisms for this stuff are so varied that
it becomes impossible to even abstract the details away behind
preprocessor macros.

What I'd like to see:

/* per structure alignment */
align(16) struct xyz {
char x;
char y;
int z;
};

Why would you "like to see" this? If you're dealing with
a particular compiler for a particular piece of hardware, you
can use whatever compiler-specific mechanisms are provided.
But if you're seeking "portable control," how portable is the
magic number 16?
[...]
so in the case of the host implementation not supporting the specified
alignment, a warning should be emitted and either the closest or
natural alignment should be given. Warnings can obviously be made
fatal with compiler specific switches - and that's no business of the
language.

If different implementations can do whatever they please with
the directive, how "portable" is it? As with register you can
write it and be assured all compilers will accept it, but as with
register you don't really know what effect it will have on the code.
It just seems that this really should be standardized as it clearly
is useful for a vast number of programmers who need to get close to the
hardware but don't want to stray into assembly code (think Altivec,
SSE).

I'm not familiar with them, but I'll suppose they're machines
with unusual and finicky alignment constraints. Very well, then:
What *one* value can you put inside an align(N) directive such that
the data will be aligned as desired on both of these machines and
on all others, too? To put it another way, if you are concerned
about such details it seems "portability" has already ceased to be
a concern.
Sounds like EXACTLY the point of the C language, doesn't it?

You'll need to ask dmr, but I don't think so.
I wouldn't mind so much if compiler implementors had come up with a
vaguely portable way of doing this, but they haven't even come close.
GCC and Intel have won joint first prize for 'most pleasant
implementation' though (__attribute__ or _declspec()).

The details of data alignment are themselves non-portable, so
the incentive to develop a portable means of controlling them seems
small. Whenever you decree that the alignment of thus-and-such
should be this-and-that, you immediately restrict the portability
of the code. All I can see is that you're proposing a portable
way to declare that a piece of code is non-portable.

Let's not pick on the proposed syntax and instead consider somewhat
practical examples. Say, I want to write - in a [more or less] portable
way - my own memset and malloc (it's a bit contrived but on occasion the
stuff that comes with the compiler is pathetic).
1. My idea of memset(dst, c, count) may be to store more than a byte at
a time, say, a 4-byte quantity at a time. To do so, I need to deal with
boundary effects: dst and (char*)dst+count are not necessarily aligned.
My instinct asks for something like ALIGN_UP(int32_t, dst) and
ALIGN_DOWN(int32_t, (char*)dst+count). [OK, assuming CHAR_BIT 8 and
mutatis mutandis otherwise.]
One can argue that my ALIGN_UP and ALIGN_DOWN can be platform-dependent
shims in an otherwise platform-independent implementation. But I'd
rather have them in a standard header, given the [] above.
2. My malloc must return a pointer aligned so that it's good for
dereferencing any type of data. So, when I obtain a pointer from my
ingenious allocation algorithm, I must ALIGN_UP it to any type. That I
don't know how to do knowing the platform alone: knowledge of the
compiler's habits is required. Since a compiler knows its own habits, it
is easier for it than for me to provide ALIGN_UP_FOR_ANY_TYPE.

<OT>
While at it: I came across a problem of the following sort. Say, every
struct in a codebase has the last member uint32_t checksum; I need a
macro that would set a member value and modify the checksum member:
STORE(pStruct, member, value).
The problem in a particular implementation is to find how far, in bytes,
pStruct->checksum from pStruct. This, of course, is
(const char *)&((pStruct)->member) - (const char *)(pStruct)
and is independent of pStruct. You'd be surprised what hoops an
otherwise respectable compiler might jump through to compute - in
runtime - this compile-time constant.
If C cannot bring itself to standardizing typeof, wouldn't it be great
to have a counterpart to offsetof that would take a pointer instead of a
type? The functionality I want is
#define ANOTHER_offsetof(p, member) offsetof(typeof(p), member).
</OT>

Regards,
-Ark
 
A

artifact.one

Eric said:
Why would you "like to see" this? If you're dealing with
a particular compiler for a particular piece of hardware, you
can use whatever compiler-specific mechanisms are provided.
But if you're seeking "portable control," how portable is the
magic number 16?

As a concrete example, GCC, Intel C, Sun C and HP C all allow
access to SSE intrinsics on x86. The code could be portable
across all these compilers except that no two of them have the
same method of specifying data alignment. The methods of
specifying data alignment are so different that it doesn't seem
to be possibly, within the realms of sanity, to actually move
source across the compilers without rewriting parts of it.
The hardware is the same, the compilers are the problem.
[...]
so in the case of the host implementation not supporting the specified
alignment, a warning should be emitted and either the closest or
natural alignment should be given. Warnings can obviously be made
fatal with compiler specific switches - and that's no business of the
language.

If different implementations can do whatever they please with
the directive, how "portable" is it? As with register you can
write it and be assured all compilers will accept it, but as with
register you don't really know what effect it will have on the code.

Well, take another concrete example. A vector math portability library.
The documentation for the library can say "use the standard
align(16) specifier to align data passed to library functions on a
16 byte boundary". The library can then do something like

if (((size_t) p) & 15)
vec_process_unaligned()
else
vec_process_aligned()

The current problem is that a vector portability library becomes a bit
of a mockery because there's no portable way to actually specify
data alignment. I agree that align() would be somewhat like register,
but I don't really see what the problem of this is? align() becomes
a "performance hint", pretty much like register.

Every compiler I can think of allows one to specify data alignment
in a compiler-specific way, so it's clearly used by many out there.
Why not standardize the means of doing it?
I'm not familiar with them, but I'll suppose they're machines
with unusual and finicky alignment constraints. Very well, then:
What *one* value can you put inside an align(N) directive such that
the data will be aligned as desired on both of these machines and
on all others, too? To put it another way, if you are concerned
about such details it seems "portability" has already ceased to be
a concern.

16 is a standard number for vector hardware. The hardware
operates on 128 bit registers so you essentially load in a packed array
of four floats that must be aligned to 16 byte boundaries. This is true
for Altivec (which is PPC), SSE (which is x86 and IA64) and 3DNow,
which is AMD-specific.
You'll need to ask dmr, but I don't think so.

So C _isn't_ for "programmers who need to get close to the
hardware but don't want to stray into assembly code"? Sorry, I'll
admit that one's a bit of a troll...
The details of data alignment are themselves non-portable, so
the incentive to develop a portable means of controlling them seems
small. Whenever you decree that the alignment of thus-and-such
should be this-and-that, you immediately restrict the portability
of the code. All I can see is that you're proposing a portable
way to declare that a piece of code is non-portable.

I'm proposing a unification of syntax so that I don't have to rewrite
source just to get it to compile on a different compiler (as I would
expect from standard C).

cheers,
MC
 
C

christian.bau

As a concrete example, GCC, Intel C, Sun C and HP C all allow
access to SSE intrinsics on x86. The code could be portable
across all these compilers except that no two of them have the
same method of specifying data alignment. The methods of
specifying data alignment are so different that it doesn't seem
to be possibly, within the realms of sanity, to actually move
source across the compilers without rewriting parts of it.
The hardware is the same, the compilers are the problem.

Just use a union.
 
A

artifact.one

christian.bau said:
Just use a union.

The only option for a union is to create a union containing
an array of four floating point integers and either a 'vector
float' (Altivec extension) or an '__m128' (SSE extension).
This places an unpleasant restriction on the client programmer
of the library because they then have to deal with an
abstract 'vec4f' type as opposed to just a properly aligned
float[].

I'd rather just be able to do align(16) float v[256];

cheers,
MC
 
E

Eric Sosman

Ark said:
Eric said:
It'd be really pleasant (in my opinion) if the next revision of the
C language actually allowed some portable control over data
alignment.

Compiler-specific mechanisms for this stuff are so varied that
it becomes impossible to even abstract the details away behind
preprocessor macros.

What I'd like to see:

/* per structure alignment */
align(16) struct xyz {
char x;
char y;
int z;
};

Why would you "like to see" this? [... assorted criticisms,
>> the burden being that a portable way to say non-portable things
>> about alignment still leaves the code non-portable ...]
Let's not pick on the proposed syntax and instead consider somewhat
practical examples.

I did not even mention the syntax, much less "pick on" it.
Say, I want to write - in a [more or less] portable
way - my own memset and malloc (it's a bit contrived but on occasion the
stuff that comes with the compiler is pathetic).

Then you're out of luck. When you try to replace such things
(and I'll grant the occasional need), you have already left any
notion of "portability" far behind. When you're trying to express
something non-portable in pursuit of a non-portable goal, there is
little advantage in doing so "portably."
 
A

artifact.one

Eric said:
Then you're out of luck. When you try to replace such things
(and I'll grant the occasional need), you have already left any
notion of "portability" far behind. When you're trying to express
something non-portable in pursuit of a non-portable goal, there is
little advantage in doing so "portably."

I can see this degenerating into triviality (if it hasn't already), but
I'd take exception to that. It may be true in the general and false in
the specific. If the implementation is allowed to ignore 'align(16)'
just as it's allowed to ignore 'register' and 'inline', it becomes a
non-issue. The code is portable in the specific (any platform
requiring 16 byte alignment for certain hardware extensions
must obviously, implicitly, support 16 byte alignment), non-portable
ONLY IF the implementation is REQUIRED to either give 16 byte
alignment or fail (the code becomes non-portable to platforms
not supporting 16 byte alignment). The non-portable aspect comes
from code _demanding_ 16 byte alignment as opposed to
_requesting_ it and working around platforms that cannot provide
it - exactly the same as the way code today can _request_
use of registers but cannot _demand_ it from the implementation.

There may be hardware out there that doesn't have more than
a single register (or any register). Should that mean that we should
ignore registers and only allow hinting at register use through
compiler-specific extensions?

Currently, these are some of the wonderful ways to specify
data alignment:

GCC:

struct abc { char a; int b; float c; };

__attribute__((aligned (16))) struct abc abc;

Sun C:

#pragma align 16 (a, b, x)

unsigned int a;
unsigned long b;
char x[16];

Intel C:

_declspec(align(16)) unsigned int x;

HP C:

#pragma HP_ALIGN HPUX_WORD PUSH
unsigned int x;
#pragma HP_ALIGN POP

IBM XL:

__align(16) unsigned int x;

Note the frivolous differences in syntax. None of these implementations
can force an unsupported alignment. They act, in effect, exactly like
'register'.

cheers,
MC
 
M

Malcolm McLean

It'd be really pleasant (in my opinion) if the next revision of the
C language actually allowed some portable control over data
alignment.

Compiler-specific mechanisms for this stuff are so varied that
it becomes impossible to even abstract the details away behind
preprocessor macros.

What I'd like to see:

/* per structure alignment */
align(16) struct xyz {
char x;
char y;
int z;
};

/* per member alignment (obviously padding before the first
member is illegal, so the entire structure would become aligned
in this case */
align(16) struct xyz {
align(16) char x;
char y;
int z;
};

/* per variable alignment */
align(16) unsigned int x;

I don't care about the syntax.

Now, obviously, C is meant to be implemented on everything from
self-aware weather-control mainframes, to motorized tie racks,
so in the case of the host implementation not supporting the specified
alignment, a warning should be emitted and either the closest or
natural alignment should be given. Warnings can obviously be made
fatal with compiler specific switches - and that's no business of the
language.

It just seems that this really should be standardized as it clearly
is useful for a vast number of programmers who need to get close to the
hardware but don't want to stray into assembly code (think Altivec,
SSE).
Sounds like EXACTLY the point of the C language, doesn't it?

I wouldn't mind so much if compiler implementors had come up with a
vaguely portable way of doing this, but they haven't even come close.
GCC and Intel have won joint first prize for 'most pleasant
implementation'
though (__attribute__ or _declspec()).
The way to do it is either
1) Have a type called moststrict_t which is always aligned properly for any
other variable. malloc() will only work if such a type exists, so whizzy new
hardware that needs types aligned on prime numbers can't be supported
anyway.

2) Have a macro void *align(ptr, type) which will take a pointer and return
the value equal to or above it suitable for storing the type in.

This can be implemented with only the tiniest of tweaks to most compilers,
and doesn't add any new syntax to the language.

Note that in practise moststrict_t is always double, so any mangement
packages will be OK if they align data to double. However it is a nuisance
to do this,
 
C

christian.bau

I'd rather just be able to do align(16) float v[256];

And how would you know that "16" is the right number, and not for
example 32 or 64?

By using a union, you can write a library that will work with existing
extensions to the C language where they exist, and doesn't require any
such extensions when they don't exist, instead of requiring a change in
the compiler everywhere.
 
A

artifact.one

christian.bau said:
I'd rather just be able to do align(16) float v[256];

And how would you know that "16" is the right number, and not for
example 32 or 64?

This is completely besides the point. I'm after a unification of
syntax,
not a technical discussion on a single piece of code. I can't really
understand the opposition to this. I appreciate the spartan
utilitarianism
of the C language, that's one of the reasons I like it so much, but I
can't understand why it's preferable for there to be 1001 incompatible
compiler extensions to specify something as basic as data alignment
instead of a single clean statement that can be ignored by the compiler
if it's not supported on the target platform. Usually I'd write a
portability
macro, but the mechanisms really are so different that this isn't
possible.

For this piece of code, it's 16 because (apparently) every current
mainstream piece of vector hardware requires 16 byte alignment.
By using a union, you can write a library that will work with existing
extensions to the C language where they exist, and doesn't require any
such extensions when they don't exist, instead of requiring a change in
the compiler everywhere.

And also burdening the library user with details that they shouldn't
have
to know about (especially if they're not even using the hardware
acceleration features of the library).

MC
 
C

Clever Monkey

christian.bau said:
I'd rather just be able to do align(16) float v[256];
And how would you know that "16" is the right number, and not for
example 32 or 64?

This is completely besides the point. I'm after a unification of
syntax,
not a technical discussion on a single piece of code. I can't really
understand the opposition to this. I appreciate the spartan
utilitarianism
of the C language, that's one of the reasons I like it so much, but I
can't understand why it's preferable for there to be 1001 incompatible
compiler extensions to specify something as basic as data alignment
instead of a single clean statement that can be ignored by the compiler
if it's not supported on the target platform. Usually I'd write a
portability
macro, but the mechanisms really are so different that this isn't
possible.

For this piece of code, it's 16 because (apparently) every current
mainstream piece of vector hardware requires 16 byte alignment.
The last ISO Forth standard introduced the notion of alignment that
would align chunks of memory on the appropriate (for the current
implementation) boundary.

So, this is not a completely foreign idea.

I admit I don't know if architectural (or other) differences between the
languages mean that such contortions in standard C are moot or nonsensical.

I do know that results of a similar gesture to malloc() in Forth can be
aligned on a legal byte boundary in a portable manner (i.e., in some
cases that ALIGN word might be a no-op). Forth has a pretty
well-defined memory model, however, so it may be that this does not
translate well to other languages.
 
T

Tim Prince

David said:
Your post is rather general and doesn't give a specific example of a
scenario where the current C mechanisms are inadequate.

Please don't make general criticisms of the language. Instead, post a
specific example of some effect or end-result you are trying to achieve and
why you believe you can't do it with the current mechanisms.

I've always found the current mechanisms to be adequate. Where alignment is
unknown or you need to do double-duty with a pointer, just define a variant
record and let the compiler figure it out ...
The current mechanisms are (sometimes) inadequate because they are
interpreted in the most unfavorable ways. For example, malloc() must
return a region "suitably" aligned for native C data types. Certain
major implementations interpret that as the minimum alignment which can
be made to work, with performance penalties, for 64-bit data types.
OTOH, there is nothing to prevent a compiler from using stack alignments
which promote performance, and malloc() writers from providing
sufficient alignments to support vectorization. Doing so is one of the
ways in which "64-bit" operating systems distinguish themselves, and are
likely to obsolete those which don't, faster than any standards could be
adopted.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top