I have a C function that generates a range from the given start
, step_size
and end
values. I use this function in a .Net app by PInvoke, therefore I want to optimize it as much as possible. I am novice SIMD programmer but intermediate in C and x86. I have written the SIMD version of it but not sure that it is well-implemented and wonder if it can be optimized further or be written more efficiently. In essence, I need a code review for the SIMD part.
typedef struct NativeFixedPointDArray_s
{
int length;
PointD_t* memory_block;
}NativeFixedPointDArray_t;
uint64_t align(uint64_t num, uint64_t alignment) {
return (num + alignment - 1) & ~(alignment - 1);
}
NativeFixedDArray_t generate_range(double start, double step_size, double end)
{
int elementsCount = (int)round((end - start) / step_size) + 1;
double* data = malloc(elementsCount * sizeof(double));
if (!data)
return (NativeFixedDArray_t) { 0, 0 };
for (int i = 0; i < elementsCount - 1; i++)
{
data[i] = start;
start += step_size;
}
data[elementsCount - 1] = end;
return (NativeFixedDArray_t) { elementsCount, data };
}
NativeFixedDArray_t generate_range_simd(double start, double step_size, double end)
{
//Calculate the number of elements that will be included in the array using start, step_size and end values.
int elementsCount = (int)round((end - start) / step_size) + 1;
// Align the number of elements with 4 for SIMD optimization.
int alignedElementsCount = align(elementsCount, 4);
double* data = malloc(alignedElementsCount * sizeof(double));
if (!data)
return (NativeFixedDArray_t) { 0, 0 };
// I need a review for this section.
__m256d start_v = _mm256_set1_pd(start);
__m256d step_size_v = _mm256_set1_pd(step_size);
for (int i = 0; i < alignedElementsCount; i += 4)
{
__m256d temp_v = _mm256_add_pd(start_v, _mm256_set_pd( step_size * (i + 3),
step_size * (i + 2),
step_size * (i + 1),
step_size * (i + 0)));
_mm256_store_pd(&data[i], temp_v);
}
data[elementsCount] = end;
return (NativeFixedDArray_t) { elementsCount, data };
}
// Here is driver program to test the functions.
int main()
{
NativeFixedDArray_t range1 = generate_range(0, 0.0002, 4.5);
NativeFixedDArray_t range2 = generate_range_simd(0, 0.0002, 4.5);
for (int i = 0; i < range1.length; ++i)
{
double value1 = range1.memory_block[i];
double value2 = range2.memory_block[i];
if (value1 != value2)
{
printf("Not equal!\n");
break;
}
printf("range1[%d]: %lf, range2[%d]: %lf\n", i, value1, i, value2);
}
return 0;
}
start + step_size * i
approach with thestart += stepsize
approach. \$\endgroup\$