1 /** 2 Module introduces memory management utilities to help manage memory for SIMD compatible arrays, 3 with or without use of GC. 4 5 Copyright: Copyright Relja Ljubobratovic 2016. 6 7 Authors: Relja Ljubobratovic 8 9 License: $(LINK3 http://www.boost.org/LICENSE_1_0.txt, Boost Software License - Version 1.0). 10 */ 11 module dcv.core.memory; 12 13 import core.simd; 14 import core.memory; 15 import core.cpuid; 16 17 import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; 18 19 /** 20 Allocate array using strict memory alignment. 21 22 Uses std.experimental.allocator.mallocator.AlignmedMallocator to 23 allocate memory. 24 25 params: 26 count = Count of elements to be allocated for the array. 27 alignment = size in bytes for memory alignment pattern. 28 29 returns: 30 Dynamic array of type T, with lenght of given count, aligned using 31 given alignment size. 32 33 note: 34 Dynamic array is not added to GC, so it has to be destoyed explicitly 35 using alignedFree. If GC is needed, use alignedAllocGC. 36 */ 37 @nogc @trusted T[] alignedAlloc(T)(size_t count, uint alignment = 16) 38 { 39 auto buff = AlignedMallocator.instance.alignedAllocate(count * T.sizeof, alignment); 40 return (cast(T*)buff)[0 .. count][]; 41 } 42 43 /** 44 Allocate array using strict memory alignment. 45 46 Uses std.experimental.allocator.mallocator.AlignmedMallocator to 47 reallocate memory. 48 Forwards to AlignedMallocator.reallocate. 49 50 params: 51 ptr = Pointer to a memory where the reallocation is to be performed at. 52 newSize = Size of the reallocated array. 53 54 returns: 55 Status of reallocation. Returns AlignedMallocator.reallocate out status. 56 */ 57 @nogc bool alignedRealloc(ref void[] ptr, size_t newSize) 58 { 59 return AlignedMallocator.instance.reallocate(ptr, newSize); 60 } 61 62 /** 63 Frees memory allocated using alignedAlloc function. 64 65 Uses AlignedMallocator.deallocate. 66 67 params: 68 ptr = Pointer to memory that is to be freed. 69 */ 70 void alignedFree(void[] ptr) @nogc 71 { 72 AlignedMallocator.instance.deallocate(ptr); 73 } 74 75 version (skipSIMD) 76 { 77 T[] allocArray(T)(size_t length) 78 { 79 return new T[length]; 80 } 81 82 void freeArray(void[] ptr) @nogc 83 { 84 ptr.destroy; 85 } 86 } 87 else 88 { 89 T[] allocArray(T)(size_t length) @trusted @nogc 90 { 91 return alignedAlloc!T(length, 16); 92 } 93 94 void freeArray(void[] ptr) @nogc 95 { 96 ptr.alignedFree; 97 } 98 } 99 100 unittest 101 { 102 // TODO: design the test... 103 104 import mir.ndslice; 105 106 int[] arr = allocArray!int(3); 107 scope (exit) 108 arr.freeArray; 109 110 auto slice = arr.sliced(3); 111 assert(&arr[0] == &slice[0]); 112 } 113 114 /** 115 * Template to get alias to SSE2 compatible vector for given type. 116 */ 117 template VectorSSE2(T) 118 { 119 import std.traits : isNumeric; 120 121 static assert(isNumeric!T, "SIMD vector has to be composed of numberic type"); 122 static if (is(T == ubyte)) 123 { 124 alias VectorSSE2 = ubyte16; 125 } 126 else static if (is(T == ushort)) 127 { 128 alias VectorSSE2 = ushort8; 129 } 130 else static if (is(T == uint)) 131 { 132 alias VectorSSE2 = uint4; 133 } 134 else static if (is(T == ulong)) 135 { 136 alias VectorSSE2 = ulong2; 137 } 138 else static if (is(T == byte)) 139 { 140 alias VectorSSE2 = byte16; 141 } 142 else static if (is(T == short)) 143 { 144 alias VectorSSE2 = short8; 145 } 146 else static if (is(T == int)) 147 { 148 alias VectorSSE2 = int4; 149 } 150 else static if (is(T == long)) 151 { 152 alias VectorSSE2 = long2; 153 } 154 else static if (is(T == float)) 155 { 156 alias VectorSSE2 = float4; 157 } 158 else static if (is(T == double)) 159 { 160 alias VectorSSE2 = double2; 161 } 162 else 163 { 164 alias VectorSSE2 = void; 165 } 166 } 167 168 /** 169 * Template to get alias to AVX compatible vector for given type. 170 */ 171 template VectorAVX(T) 172 { 173 import std.traits : isNumeric; 174 175 static assert(isNumeric!T, "SIMD vector has to be composed of numberic type"); 176 static if (is(T == ubyte)) 177 { 178 alias VectorAVX = ubyte32; 179 } 180 else static if (is(T == ushort)) 181 { 182 alias VectorAVX = ushort16; 183 } 184 else static if (is(T == uint)) 185 { 186 alias VectorAVX = uint8; 187 } 188 else static if (is(T == ulong)) 189 { 190 alias VectorAVX = ulong4; 191 } 192 else static if (is(T == byte)) 193 { 194 alias VectorAVX = byte32; 195 } 196 else static if (is(T == short)) 197 { 198 alias VectorAVX = short16; 199 } 200 else static if (is(T == int)) 201 { 202 alias VectorAVX = int8; 203 } 204 else static if (is(T == long)) 205 { 206 alias VectorAVX = long4; 207 } 208 else static if (is(T == float)) 209 { 210 alias VectorAVX = float8; 211 } 212 else static if (is(T == double)) 213 { 214 alias VectorAVX = double4; 215 } 216 else 217 { 218 alias VectorAVX = void; 219 } 220 } 221 222 enum size_t vectorSize(T) = T.init.length;