CPUs often support specialized vector types and vector operations (aka media instructions). Vector types are a fixed array of floating or integer types, and vector operations operate simultaneously on them.
alias int4 = __vector(int[4]);
All the basic integer types can be used as base types, both as signed and as
unsigned: byte
, short
, int
, long
. In addition,
float
and double
can be used to build floating-point vector
types, and void
to build vectors of untyped data. Only sizes that are
positive power-of-two multiples of the base type size are currently allowed.
The core.simd
module has the following shorthand aliases for commonly
supported vector types:
byte8
, byte16
, byte32
, byte64
,
double1
, double2
, double4
, double8
,
float2
, float4
, float8
, float16
,
int2
, int4
, int8
, int16
,
long1
, long2
, long4
, long8
,
short4
, short8
, short16
, short32
,
ubyte8
, ubyte16
, ubyte32
, ubyte64
,
uint2
, uint4
, uint8
, uint16
,
ulong1
, ulong2
, ulong4
, ulong8
,
ushort4
, ushort8
, ushort16
, ushort32
,
void8
, void16
, void32
, void64
.
All these aliases correspond to __vector(type[N])
.
Which vector types are supported depends on the target. Only vector types that are implemented for the current architecture are supported at compile-time. Vector operations that are not supported in hardware cause GNU D to synthesize the instructions using a narrower mode.
alias v4i = __vector(int[4]); alias v128f = __vector(float[128]); // Error: not supported on this platform int4 a, b, c; c = a * b; // Natively supported on x86 with SSE4 c = a / b; // Always synthesized
Vector types can be used with a subset of normal D operations. Currently, GNU
D allows using the following operators on these types: +, -, *, /,
unary+, unary-
.
alias int4 = __vector(int[4]); int4 a, b, c; c = a + b;
It is also possible to use shifting operators <<
, >>
, the modulus
operator %
, logical operations &, |, ^
, and the complement
operator unary~
on integer-type vectors.
For convenience, it is allowed to use a binary vector operation where one operand is a scalar. In that case the compiler transforms the scalar operand into a vector where each element is the scalar from the operation. The transformation happens only if the scalar could be safely converted to the vector-element type. Consider the following code.
alias int4 = __vector(int[4]); int4 a, b; long l; a = b + 1; // a = b + [1,1,1,1]; a = 2 * b; // a = [2,2,2,2] * b; a = l + a; // Error, incompatible types.
Vector comparison is supported with standard comparison operators:
==, !=, <, <=, >, >=
. Comparison operands can be vector expressions of
integer-type or real-type. Comparison between integer-type vectors and
real-type vectors are not supported. The result of the comparison is a vector
of the same width and number of elements as the comparison operands with a
signed integral element type.
Vectors are compared element-wise producing 0 when comparison is false and -1 (constant of the appropriate type where all bits are set) otherwise. Consider the following example.
alias int4 = __vector(int[4]); int4 a = [1,2,3,4]; int4 b = [3,2,1,4]; int4 c; c = a > b; // The result would be [0, 0,-1, 0] c = a == b; // The result would be [0,-1, 0,-1]