Есть ли способ в C проверить во время компиляции, если вы находитесь в архитектуре, где умножение происходит быстро?

Есть ли способ для кода C определить, компилируется ли он в архитектуре, где умножение происходит быстро? Есть ли макрос __FAST_MULT__ или что-то, что определено на этих архитектурах?

Например, предположим, что вы реализуете функцию для определения веса Хэмминга 64-битного целого с помощью метода shift-and-add *. Существуют два оптимальных алгоритма для этого: требуется 17 арифметических операций, а для другого требуется только 12, но одна из них - операция умножения. Второй алгоритм, таким образом, на 30% быстрее, если вы работаете на оборудовании, где умножение занимает такое же количество времени, что и добавление, но гораздо медленнее в системе, где умножение реализуется как повторное добавление. Таким образом, при написании такой функции было бы полезно иметь возможность проверять во время компиляции, является ли это так, и переключаться между двумя алгоритмами, если это необходимо:

unsigned int popcount_64(uint64_t x) {
    x -= (x >> 1) & 0x5555555555555555;                             // put count of each 2 bits into those 2 bits
    x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); // put count of each 4 bits into those 4 bits
    x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;                        // put count of each 8 bits into those 8 bits
#ifdef __FAST_MULT__
    return (x * 0x0101010101010101)>>56;                            // returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
#else // __FAST_MULT__
    x += x >>  8;                                                   // put count of each 16 bits into their lowest 8 bits
    x += x >> 16;                                                   // put count of each 32 bits into their lowest 8 bits
    x += x >> 32;                                                   // put count of each 64 bits into their lowest 8 bits
    return x & 0x7f;
#endif // __FAST_MULT__
}

Есть ли способ сделать это?

* Да, я знаю функции __builtin_popcount(); это просто пример.

Ответ 1

Есть ли способ для кода C определить, компилируется ли он в архитектуре, где умножение происходит быстро? Есть ли макрос __FAST_MULT__ или что-то, что определено на этих архитектурах?

Нет, стандарт C не предоставляет такого объекта. Возможно, что определенные компиляторы предоставляют такую ​​вещь, как расширение, но я не знаю о том, что на самом деле делать.

Такие вещи можно протестировать во время конфигурации сборки, например, через Autoconf или CMake, и в этом случае вы можете предоставить символ самостоятельно, если это необходимо.

В качестве альтернативы некоторые компиляторы C определенно предоставляют макросы, которые указывают на архитектуру, для которой компилируется код. Вы можете использовать это в сочетании со знанием деталей различных архитектур машин, чтобы выбрать между двумя алгоритмами - что все эти макросы предназначены для всех.

Или вы можете положиться на человека, который строит программу, чтобы выбрать по параметру конфигурации, задав макрос или что-то еще.

Ответ 2

Я не верю, что существует предопределенный макрос, специально предназначенный для функции быстрого умножения.

Однако существует много предопределенных макросов компилятора для разных архитектур, поэтому, если вы уже заранее знаете, какие архитектуры или процессоры поддерживают быстрый умножения, вы можете использовать эти макросы, чтобы определить свой собственный специфичный для приложения, который означает быстрое умножение.

например:.

#if (defined __GNUC__ && defined __arm__ && defined __ARM_ARCH_'7'__) ||
    (defined __CC_ARM && (__TARGET_ARCH_ARM == 7))
#define FAST_MULT
#endif