Pointer alignments in the type system?

bearophile bearophileHUGS at lycos.com
Mon Jun 24 05:03:09 PDT 2013


Lately I am playing a little with SIMD in D, and with the work in 
progress module std.simd, and I have added several related bug 
reports to Bugzilla.

This program compiles with no errors nor warnings with ldc2 on 
Windows32 bit:


import core.simd;

__gshared immutable int[16]
     a = [ 1,  2,  3,  4,  5,  6,  7,  8, 9, 10, 11, 12, 13, 14, 
15, 16],
     b = [16, 15, 14, 13, 12, 11, 10,  9, 8,  7,  6,  5,  4,  3,  
2,  1];
__gshared int[16] c;

void main() {
     auto va = cast(int4[])a;
     auto vb = cast(int4[])b;
     auto vc = cast(int4[])c;
     vc[0] = va[0] + vb[0];
}


ldc2 generates this main:

__Dmain:
     subl    $12, %esp
     movl    $16, 8(%esp)
     movl    $4, 4(%esp)
     movl    $16, (%esp)
     calll   __d_array_cast_len
     movdqa  __D5test51ayG16i, %xmm0
     paddd   __D5test51byG16i, %xmm0
     movdqa  %xmm0, __D5test51cG16i
     xorl    %eax, %eax
     addl    $12, %esp
     ret


It uses the instruction movdqa, that assumes a,b and c to be 
aligned to 16 bytes. But I think there is no guarantee they are.

This is the LL code generated using the -output-ll switch of ldc2 
(it's a kind of nearly universal bytecode for llvm):

@_D5test51ayG16i = global [16 x i32] [i32 1, i32 2, i32 3, i32 4, 
i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 
13, i32 14, i32 15, i32 16]
@_D5test51byG16i = global [16 x i32] [i32 16, i32 15, i32 14, i32 
13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, 
i32 4, i32 3, i32 2, i32 1]
@_D5test51cG16i = global [16 x i32] zeroinitializer


If I add a "align(16)" annotation to a, b, c it adds the align 16 
annotation in the LL code too:

@_D5test51ayG16i = global [16 x i32] [i32 1, i32 2, i32 3, i32 4, 
i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 
13, i32 14, i32 15, i32 16], align 16
@_D5test51byG16i = global [16 x i32] [i32 16, i32 15, i32 14, i32 
13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, 
i32 4, i32 3, i32 2, i32 1], align 16
@_D5test51cG16i = global [16 x i32] zeroinitializer, align 16


Instead of array casts if I cast the pointers the result is 
similar, but there is no call to __d_array_cast_len (this is a 
raw cast, so I don't expect much help from the type system 
here...):

     auto va = cast(int4*)a.ptr;
     auto vb = cast(int4*)b.ptr;
     auto vc = cast(int4*)c.ptr;


I'd like to receive an alignment warning in those cast(int4[]), 
or the compiler should not use movdqa in such case. This means 
that maybe __d_array_cast_len should keep and transmit the 
alignment of its input pointer to the pointer in the output 
array. And maybe this means the D front-end should keep an 
alignment information for each pointer (or for pointers that will 
be used in situations where the alignment is important), 
integrating it in its type system (and perhaps perform alignment 
inference like the purity inference done for function templates).

The alignment of pointers is important for the CPU, so maybe the 
type system of a system language should keep track of them, and 
enforce the correctness of the alignments. Maybe this could be 
done with no further annotation burden for the programmer. A 
potential problem is how to mix this alignment inference with the 
needs of separate compilation. I think the align() annotations 
suffice for that.

Bye,
bearophile


More information about the Digitalmars-d mailing list