Получить GCC использовать Carry Logic для произвольной точности арифметики без встроенной сборки?

Работая с арифметикой произвольной точности (например, 512-битными целыми числами), есть ли способ заставить GCC использовать АЦП и подобные инструкции без использования встроенной сборки?

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

Вот тестовый код, который я написал, который добавляет два 128-битных числа из командной строки и печатает результат. (Вдохновлено add_n от mini-gmp):

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main (int argc, char **argv)
{
    uint32_t a[4];
    uint32_t b[4];
    uint32_t c[4];
    uint32_t carry = 0;

    for (int i = 0; i < 4; ++i)
    {
        a[i] = strtoul (argv[i+1], NULL, 16);
        b[i] = strtoul (argv[i+5], NULL, 16);
    }

    for (int i = 0; i < 4; ++i)
    {
        uint32_t aa = a[i];
        uint32_t bb = b[i];
        uint32_t r = aa + carry;
        carry = (r < carry);
        r += bb;
        carry += (r < bb);
        c[i] = r;
    }

    printf ("%08X%08X%08X%08X + %08X%08X%08X%08X =\n", a[3], a[2], a[1], a[0], b[3], b[2], b[1], b[0]);
    printf ("%08X%08X%08X%08X\n", c[3], c[2], c[1], c[0]);

    return 0;
}

GCC -O3 -std=c99 Не производит никаких adc инструкции, проверенные objdump, Моя версия gcc i686-pc-mingw32-gcc (GCC) 4.5.2,

1 ответ

GCC будет использовать флаг переноса, если увидит, что ему необходимо:
При добавлении двух uint64_t значения на 32-битном компьютере, например, это должно привести к одному 32-битному ADD плюс один 32-разрядный ADC, Но кроме тех случаев, когда компилятор вынужден использовать перенос, его, вероятно, нельзя убедить сделать это без ассемблера. Следовательно, может быть полезно использовать самый большой целочисленный тип из доступных, чтобы позволить GCC оптимизировать операции, эффективно сообщая ему, что отдельные "компоненты" значения принадлежат друг другу.

Для простого сложения еще одним способом вычисления переноса может быть просмотр соответствующих битов в операндах, например:

uint32_t aa,bb,rr;
bool msbA, msbB, msbR, carry;
// ...

rr = aa+bb;

msbA = aa >= (1<<31); // equivalent: (aa & (1<<31)) != 0;
msbB = bb >= (1<<31);
msbR = rr >= (1<<31);


carry = (msbA && msbB) || ( !msbR && ( msbA || msbB) );
Другие вопросы по тегам