Оптимизация прочь memcpy - PullRequest
       8

Оптимизация прочь memcpy

0 голосов
/ 27 ноября 2018

В попытке избежать нарушения строгих правил псевдонимов, я ввел memcpy в пару мест в своем коде, ожидая, что это не будет.В следующем примере вызывается memcpy (или эквивалентный) для gcc и clang.В частности, fool<40> всегда работает, в то время как foo работает на gcc, но не на clang, а fool<2> на clang, но не на gcc.Когда и как это можно оптимизировать?

uint64_t bar(const uint16_t *buf) {
  uint64_t num[2];
  memcpy(&num, buf, 16);
  return num[0] + num[1];
}

uint64_t foo(const uint16_t *buf) {
  uint64_t num[3];
  memcpy(&num, buf, sizeof(num));
  return num[0] + num[1];
}

template <int SZ>
uint64_t fool(const uint16_t *buf) {
  uint64_t num[SZ];
  memcpy(&num, buf, sizeof(num));
  uint64_t ret = 0;
  for (int i = 0; i < SZ; ++i)
    ret += num[i];
  return ret;
}

template uint64_t fool<2>(const uint16_t*);
template uint64_t fool<40>(const uint16_t*);

И ссылка на скомпилированный вывод (Godbolt).

1 Ответ

0 голосов
/ 27 ноября 2018

Я не могу сказать, почему именно соответствующие компиляторы не могут оптимизировать код так, как вы надеетесь оптимизировать его в конкретных случаях.Я предполагаю, что каждый компилятор либо просто не может отследить отношения, установленные memcpy между целевым массивом и исходной памятью (как мы можем видеть, они, кажется, распознают эту связь, по крайней мере, в некоторых случаях), либо у них просто есть какое-то эвристическое сообщениеони решили не использовать его.

В любом случае, поскольку компиляторы, похоже, не ведут себя так, как мы надеемся, когда мы полагаемся на то, что они отслеживают весь массив, мы можем попытаться сделать его более очевиднымкомпилятору, просто выполняя memcpy для каждого элемента.Это , похоже, дает желаемый результат на обоих компиляторах .Обратите внимание, что мне пришлось вручную развернуть инициализацию в bar и foo, поскольку в противном случае clang снова сделает копию.

Кроме того, обратите внимание, что в C ++ вы должны использовать std::memcpy, std::uint64_tи т. д., поскольку стандартные заголовки не гарантируют также внесения этих имен в глобальное пространство имен (хотя я не знаю ни одной реализации, которая этого не делает).

...