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