| // GNU D Compiler SIMD support functions and intrinsics. | |
| // Copyright (C) 2022-2026 Free Software Foundation, Inc. | |
| // GCC is free software; you can redistribute it and/or modify it under | |
| // the terms of the GNU General Public License as published by the Free | |
| // Software Foundation; either version 3, or (at your option) any later | |
| // version. | |
| // GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| // for more details. | |
| // Under Section 7 of GPL version 3, you are granted additional | |
| // permissions described in the GCC Runtime Library Exception, version | |
| // 3.1, as published by the Free Software Foundation. | |
| // You should have received a copy of the GNU General Public License and | |
| // a copy of the GCC Runtime Library Exception along with this program; | |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| // <http://www.gnu.org/licenses/>. | |
| module gcc.simd; | |
| pure: | |
| nothrow: | |
| @safe: | |
| @nogc: | |
| pragma(inline, true): | |
| /** | |
| * Emit prefetch instruction. | |
| * Params: | |
| * address = address to be prefetched | |
| * writeFetch = true for write fetch, false for read fetch | |
| * locality = 0..3 (0 meaning least local, 3 meaning most local) | |
| */ | |
| void prefetch(bool writeFetch, ubyte locality)(const(void)* address) | |
| { | |
| static assert(locality < 4, "0..3 expected for locality"); | |
| import gcc.builtins : __builtin_prefetch; | |
| __builtin_prefetch(address, writeFetch, locality); | |
| } | |
| /** | |
| * Load unaligned vector from address. | |
| * This is a compiler intrinsic. | |
| * Params: | |
| * p = pointer to vector | |
| * Returns: | |
| * vector | |
| */ | |
| V loadUnaligned(V)(const V* p) if (isVectorType!V); | |
| /** | |
| * Store vector to unaligned address. | |
| * This is a compiler intrinsic. | |
| * Params: | |
| * p = pointer to vector | |
| * value = value to store | |
| * Returns: | |
| * value | |
| */ | |
| V storeUnaligned(V)(V* p, V value) if (isVectorType!V); | |
| /** | |
| * Construct a permutation of elements from one or two vectors, returning a | |
| * vector of the same type as the input vector(s). The `mask` is an integral | |
| * vector with the same width and element count as the output vector. | |
| * Params: | |
| * op1 = input vector | |
| * op2 = input vector | |
| * mask = integer vector mask | |
| * Returns: | |
| * vector with the same type as `op1` and `op2` | |
| * Example: | |
| * --- | |
| * int4 a = [1, 2, 3, 4]; | |
| * int4 b = [5, 6, 7, 8]; | |
| * int4 mask1 = [0, 1, 1, 3]; | |
| * int4 mask2 = [0, 4, 2, 5]; | |
| * assert(shuffle(a, mask1).array == [1, 2, 2, 4]); | |
| * assert(shuffle(a, b, mask2).array == [1, 5, 3, 6]); | |
| * --- | |
| */ | |
| template shuffle(V0, V1, M) | |
| { | |
| static assert(isVectorType!V0, "first argument must be vector"); | |
| static assert(isVectorType!V1, "second argument must be vector"); | |
| static assert(is(BaseType!V0 == BaseType!V1), | |
| "first and second argument vectors must have the same element type"); | |
| static assert(isVectorType!M && is(BaseType!M : long), | |
| "last argument must be an integer vector"); | |
| static assert(numElements!V0 == numElements!M && numElements!V1 == numElements!M, | |
| "argument vectors and mask vector should have the same number of elements"); | |
| static assert(BaseType!V0.sizeof == BaseType!M.sizeof, | |
| "argument vectors and mask vector should have the same element type size"); | |
| V0 shuffle(V0 op1, V1 op2, M mask); | |
| } | |
| /// Ditto | |
| template shuffle(V, M) | |
| { | |
| static assert(isVectorType!V, "first argument must be a vector"); | |
| static assert(isVectorType!M && is(BaseType!M : long), | |
| "last argument must be an integer vector"); | |
| static assert(numElements!V == numElements!M, | |
| "argument vector and mask vector should have the same number of elements"); | |
| static assert(BaseType!V.sizeof == BaseType!M.sizeof, | |
| "argument vector and mask vector should have the same element type size"); | |
| V shuffle(V op1, M mask) | |
| { | |
| return shuffle(op1, op1, mask); | |
| } | |
| } | |
| /** | |
| * Construct a permutation of elements from two vectors, returning a vector with | |
| * the same element type as the input vector(s), and same length as the `mask`. | |
| * Params: | |
| * op1 = input vector | |
| * op2 = input vector | |
| * index = elements indices of the vectors that should be extracted and returned | |
| * Returns: | |
| * vector with the same element type as `op1` and `op2`, but has an element count | |
| * equal to the number of indices in `index`. | |
| * Example: | |
| * --- | |
| * int8 a = [1, -2, 3, -4, 5, -6, 7, -8]; | |
| * int4 b = shufflevector(a, a, 0, 2, 4, 6); | |
| * assert(b.array == [1, 3, 5, 7]); | |
| * int4 c = [-2, -4, -6, -8]; | |
| * int d = shufflevector(c, b, 4, 0, 5, 1, 6, 2, 7, 3); | |
| * assert(d.array == a.array); | |
| * --- | |
| */ | |
| template shufflevector(V1, V2, M...) | |
| { | |
| static assert(isVectorType!V1, "first argument must be vector"); | |
| static assert(isVectorType!V2, "second argument must be vector"); | |
| static assert(is(BaseType!V1 == BaseType!V2), | |
| "first and second argument vectors must have the same element type"); | |
| static assert(isPowerOf2!(M.length), | |
| "number of index arguments must be a power of 2"); | |
| __vector(BaseType!V1[M.length]) shufflevector(V1 op1, V2 op2, M index); | |
| } | |
| /// Ditto | |
| template shufflevector(V, index...) | |
| { | |
| // Defined for compatibility with LDC. | |
| static assert(isVectorType!V, "first argument must be a vector type"); | |
| static assert(numElements!V == index.length, | |
| "number of index arguments must be the same number of vector elements"); | |
| private template ctfeConstants(m...) | |
| { | |
| static if (m.length == 0) enum ctfeConstants = 1; | |
| else enum ctfeConstants = m[0] | ctfeConstants!(m[1 .. $]); | |
| } | |
| static assert(__traits(compiles, ctfeConstants!index), | |
| "all index arguments must be compile time constants"); | |
| private template validIndexes(m...) | |
| { | |
| static if (m.length == 0) enum validIndexes = true; | |
| else enum validIndexes = (cast(long)m[0] > -1) && validIndexes!(m[1 .. $]); | |
| } | |
| static assert(validIndexes!index, | |
| "all index arguments must be greater than or equal to 0"); | |
| V shufflevector(V op1, V op2) | |
| { | |
| return shufflevector(op1, op2, index); | |
| } | |
| } | |
| /** | |
| * Extracts a single scalar element from a vector at a specified index. | |
| * Defined for compatibility with LDC. | |
| * Params: | |
| * val = vector to extract element from | |
| * idx = index indicating the position from which to extract the element | |
| * Returns: | |
| * scalar of the same type as the element type of val | |
| * Example: | |
| * --- | |
| * int4 a = [0, 10, 20, 30]; | |
| * int k = extractelement!(int4, 2)(a); | |
| * assert(k == 20); | |
| * --- | |
| */ | |
| BaseType!V extractelement(V, int idx)(V val) | |
| if (isVectorType!V && idx < numElements!V) | |
| { | |
| return val[idx]; | |
| } | |
| /** | |
| * Inserts a scalar element into a vector at a specified index. | |
| * Defined for compatibility with LDC. | |
| * Params: | |
| * val = vector to assign element to | |
| * elt = scalar whose type is the element type of val | |
| * idx = index indicating the position from which to extract the element | |
| * Returns: | |
| * vector of the same type as val | |
| * Example: | |
| * --- | |
| * int4 a = [0, 10, 20, 30]; | |
| * int4 b = insertelement!(int4, 2)(a, 50); | |
| * assert(b.array == [0, 10, 50, 30]); | |
| * --- | |
| */ | |
| V insertelement(V, int idx)(V val, BaseType!V elt) | |
| if (isVectorType!V && idx < numElements!V) | |
| { | |
| val[idx] = elt; | |
| return val; | |
| } | |
| /** | |
| * Convert a vector from one integral or floating vector type to another. | |
| * The result is an integral or floating vector that has had every element | |
| * cast to the element type of the return type. | |
| * Params: | |
| * from = input vector | |
| * Returns: | |
| * converted vector | |
| * Example: | |
| * --- | |
| * int4 a = [1, -2, 3, -4]; | |
| * float4 b = [1.5, -2.5, 3, 7]; | |
| * assert(convertvector!float4(a).array == [1, -2, 3, -4]); | |
| * assert(convertvector!double4(a).array == [1, -2, 3, -4]); | |
| * assert(convertvector!double4(b).array == [1.5, -2.5, 3, 7]); | |
| * assert(convertvector!int4(b).array == [1, -2, 3, 7]); | |
| * --- | |
| */ | |
| template convertvector(V, T) | |
| { | |
| static assert(isVectorType!V && (is(BaseType!V : long) || is(BaseType!V : real)), | |
| "first argument must be an integer or floating vector type"); | |
| static assert(isVectorType!T && (is(BaseType!T : long) || is(BaseType!T : real)), | |
| "second argument must be an integer or floating vector"); | |
| static assert(numElements!V == numElements!T, | |
| "first and second argument vectors should have the same number of elements"); | |
| V convertvector(T); | |
| } | |
| /** | |
| * Construct a conditional merge of elements from two vectors, returning a | |
| * vector of the same type as the input vector(s). The `mask` is an integral | |
| * vector with the same width and element count as the output vector. | |
| * Params: | |
| * op1 = input vector | |
| * op2 = input vector | |
| * mask = integer vector mask | |
| * Returns: | |
| * vector with the same type as `op1` and `op2` | |
| * Example: | |
| * --- | |
| * int4 a = [1, 2, 3, 4]; | |
| * int4 b = [5, 6, 7, 8]; | |
| * int4 mask1 = [0, 1, 1, 3]; | |
| * int4 mask2 = [0, 4, 2, 5]; | |
| * assert(shuffle(a, mask1).array == [1, 2, 2, 4]); | |
| * assert(shuffle(a, b, mask2).array == [1, 5, 3, 6]); | |
| * --- | |
| */ | |
| template blendvector(V0, V1, M) | |
| { | |
| static assert(isVectorType!V0, "first argument must be vector"); | |
| static assert(isVectorType!V1, "second argument must be vector"); | |
| static assert(is(BaseType!V0 == BaseType!V1), | |
| "first and second argument vectors must have the same element type"); | |
| static assert(isVectorType!M && is(BaseType!M : long), | |
| "last argument must be an integer vector"); | |
| static assert(numElements!V0 == numElements!M && numElements!V1 == numElements!M, | |
| "argument vectors and mask vector should have the same number of elements"); | |
| static assert(BaseType!V0.sizeof == BaseType!M.sizeof, | |
| "argument vectors and mask vector should have the same element type size"); | |
| V0 blendvector(V0 op1, V1 op2, M mask); | |
| } | |
| /** | |
| * Perform an element-wise comparison between two vectors, producing `0` when | |
| * the comparison is false and `-1` (all bits are set to 1) otherwise. | |
| * Params: | |
| * op1 = input vector | |
| * op2 = input vector | |
| * Returns: | |
| * vector of the same width and number of elements as the comparison | |
| * operands with a signed integral element type | |
| * Example: | |
| * --- | |
| * float4 a = [1, 3, 5, 7]; | |
| * float4 b = [2, 3, 4, 5]; | |
| * int4 c = greaterMask!float4(a, b); | |
| * assert(c.array == [0, 0, -1, -1]); | |
| * --- | |
| */ | |
| V equalMask(V)(V op1, V op2) if (isVectorType!V) | |
| { | |
| return op1 == op2; | |
| } | |
| /// Ditto | |
| V notEqualMask(V)(V op1, V op2) if (isVectorType!V) | |
| { | |
| return op1 != op2; | |
| } | |
| /// Ditto | |
| V greaterMask(V)(V op1, V op2) if (isVectorType!V) | |
| { | |
| return op1 > op2; | |
| } | |
| /// Ditto | |
| V greaterOrEqualMask(V)(V op1, V op2) if (isVectorType!V) | |
| { | |
| return op1 >= op2; | |
| } | |
| /** | |
| * Perform an element-wise logical comparison between two vectors, producing | |
| * `0` when the comparison is false and `-1` (all bits are set to 1) otherwise. | |
| * Params: | |
| * op1 = input vector | |
| * op2 = input vector | |
| * Returns: | |
| * vector of the same width and number of elements as the comparison | |
| * operands with a signed integral element type | |
| */ | |
| V notMask(V)(V op1) if (isVectorType!V) | |
| { | |
| return op1 == 0; | |
| } | |
| /// Ditto | |
| V andAndMask(V)(V op1, V op2) if (isVectorType!V) | |
| { | |
| return (op1 != 0) & (op2 != 0); | |
| } | |
| /// Ditto | |
| V orOrMask(V)(V op1, V op2) if (isVectorType!V) | |
| { | |
| return (op1 != 0) | (op2 != 0); | |
| } | |
| // Private helper templates. | |
| private: | |
| enum bool isVectorType(T) = is(T : __vector(V[N]), V, size_t N); | |
| template BaseType(V) | |
| { | |
| alias typeof(V.array[0]) BaseType; | |
| } | |
| template numElements(V) | |
| { | |
| enum numElements = V.sizeof / BaseType!(V).sizeof; | |
| } | |
| enum bool isPowerOf2(int Y) = Y && (Y & -Y) == Y; |