У меня есть простая структура для хранения массива:
struct array_of_a_type {
size_t allocated_size;
size_t elements; /* 1-index based */
a_type *array;
};
Я хочу написать простую функцию, примерно такую:
bool simple_function(struct array_of_a_type *my_array, int a, int b, int c, int d)
{
a_type new_chunk[] = {
a, b, a+b, d, c,
c, c, c+d, b+d, a,
a+c, b+c, c+d, c+d, c,
};
size_t size = sizeof(new_chunk) / sizeof(a_type);
return push_to_array(my_array, new_chunk, size);
}
my_array - статическая глобальная переменная. Ниже приведена реализация push_to_array.
static bool push_to_array(struct array_of_a_type *a, a_type *new_chunk, size_t size)
{
const size_t new_size = a->elements + size;
const size_t old_size = a->elements;
if (new_size > a->allocated_size) {
/* The allocated_size is most of the time big enough.
I’ve stripped this part of code to minimum. */
a_type *tmp = realloc(a->array, new_size * sizeof(a_type));
if (!tmp) {
return true;
} else {
a->array = tmp;
a->allocated_size = new_size;
}
}
a->elements = new_size;
memcpy(a->array + old_size, new_chunk, size * sizeof(a_type));
return false;
}
Мой вопрос:
Как я могу переписать 'simple_function, чтобы сделать больше компиляторов сгенерировать код, который будет писать непосредственно в пункт назначения? Я бы хотел, чтобы код оставался довольно коротким и гибким.
Мой код работает. К сожалению, gcc (и старый clang) создают временные данные в стеке, а затем копируют его в пункт назначения. Ниже, если фрагмент сгенерированного ассемблера x86_64.
movq 8(%rsp), %rdx
movq %rdx, 8(%rax)
movq 16(%rsp), %rdx
movq %rdx, 16(%rax)
movq 24(%rsp), %rdx
movq %rdx, 24(%rax)
movq 32(%rsp), %rdx
movq %rdx, 32(%rax)
Для AMD ассемблер имеет это:
rep movsq
Новый кланг отлично работает. Я скомпилирован с -O3.
Я попытался с кодом, который добавил один элемент за раз. К сожалению, было много условных переходов для вызова realloc.