Pointer alignments in the type system?

bearophile bearophileHUGS at lycos.com
Fri Aug 16 09:38:59 PDT 2013


Manu:

> I'm not sure about the warning, it doesn't really sound right 
> to me. Maybe
> it would be useful... or maybe it would be annoying.
> A cast is a cast, it is a deliberate act of reinterpretation... 
> the user
> needs to take some responsibility in this case.

OK.


> What happens if you do:
>   int[16] a = [ 1,  2,  3,  4,  5,  6,  7,  8, 9, 10, 11, 12, 
> 13, 14, 15,
> 16];
>   auto va = cast(int4[])a[1..$]; // ?? .. the offset breaks the 
> alignment.
> (and now it's too short)

If you use a[16..$] or a[32..$] then the compiler knows 
statically that the slice has kept the 16 bytes alignment.
If you use a[i..$] where i is a run-time value, then the compiler 
assumes the worst, that a is aligned to 4 bytes.
A kind of cast could be used to force the compiler assume a 
certain pointer/array has a certain alignment (better languages 
could allow you to write a proof of such alignment, but this is 
not possible in D, unless you add something like the Microsoft Z3 
solver inside the compiler).


> Yes, kinda like I was saying above. It might be fine if you are 
> explicit
> with align() statements, but whenever you are sharing pointers 
> between link
> units, how can you ever retain the information the compiler 
> needs?

The title of this thread is "Pointer alignments in the type 
system", that means that the static information of the alignment 
is kept with the type of the pointers/arrays (including dynamic 
arrays). In D you can use int[3] across link units because the 
length is part of the static information of the array.

To make things back-ward compatible you need a "don't know" 
alignment, that is like the "void*" type for pointers, or maybe 
for the minimum alignment you could just use the natural 
alignment of the type.

See some my successive posts for some examples.


> I think it's a mistake to make it work in some cases and not 
> others.

I agree. My proposal is to make them always work (unless you 
destroy the static information with a cast or a runtime-valued 
slicing). Runtime functions like "idup" etc are supposed to keep 
and "transmit" the alignment information.


> So for
> this reason, I maintain that the user just needs to take 
> responsibility for their casts...

In D we have a good static type system, unlike for example in 
Python2. One of the points of a static type system is to keep 
some static information, to use it to enforce certain invariants 
statically, and avoid some bugs and offer performance. SIMD 
programming works more efficiently with certain alignments. In my 
opinion it's not too much hard to retain such alignment 
information and avoid certain bugs statically, and produce fast 
code. Having a static type system and not using it is a waste.

This means this a will has a standard aliment of 16:
auto a = new int[128];
static assert(__traits(alignment, a) == 16);

this b has a statically knwn alignment of 4:
auto b = a[i .. $];
static assert(__traits(alignment, b) == 4);
auto b2 = cast(align(16))b;
static assert(__traits(alignment, b2) == 16);

This c has a statically known alignment of 16:
auto c = a.dup;
static assert(__traits(alignment, c) == 16);

auto d = new align(32) int[128]; // A possible syntax.
static assert(__traits(alignment, d) == 32);
// Other possible syntax:
auto d2 = new int[128] align(32);
auto d3 = new int[128]<32>;

auto e = d[64..$];
static assert(__traits(alignment, e) == 32);

align(32) int[128] f;
static assert(__traits(alignment, f) == 32);

Bye,
bearophile


More information about the Digitalmars-d mailing list