Деление divdi3 долго использовалось gcc на x86

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

http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html

По ссылке выше, long __divdi3 (long a, long b) используется для деления длинных. Однако здесь http://gcc.gnu.org/onlinedocs/gcc-3.3/gccint/Library-Calls.html divdi объясняется как "призыв к разделению одного двойного слова со знаком". Когда первый источник имеет четкое отображение суффикса di -> длинных аргументов, второй сообщает divdi для двойного слова и udivdi для полного слова (single, right?)

Когда я собираю простой пример

int main(int argc, char *argv[]) {
    long long t1, t2, tr;

    t1 = 1;
    t2 = 1;
    tr = t1 / t2;

    return tr;
}

с gcc -Wall -O0 -m32 -march=i386 (gcc ver. 4.7.2) disamble показывает мне

    080483cc <main>:
     80483cc:       55                      push   %ebp
     80483cd:       89 e5                   mov    %esp,%ebp
     80483cf:       83 e4 f0                and    $0xfffffff0,%esp
     80483d2:       83 ec 30                sub    $0x30,%esp
     80483d5:       c7 44 24 28 01 00 00    movl   $0x1,0x28(%esp)
     80483dc:       00
     80483dd:       c7 44 24 2c 00 00 00    movl   $0x0,0x2c(%esp)
     80483e4:       00
     80483e5:       c7 44 24 20 01 00 00    movl   $0x1,0x20(%esp)
     80483ec:       00
     80483ed:       c7 44 24 24 00 00 00    movl   $0x0,0x24(%esp)
     80483f4:       00
     80483f5:       8b 44 24 20             mov    0x20(%esp),%eax
     80483f9:       8b 54 24 24             mov    0x24(%esp),%edx
     80483fd:       89 44 24 08             mov    %eax,0x8(%esp)
     8048401:       89 54 24 0c             mov    %edx,0xc(%esp)
     8048405:       8b 44 24 28             mov    0x28(%esp),%eax
     8048409:       8b 54 24 2c             mov    0x2c(%esp),%edx
     804840d:       89 04 24                mov    %eax,(%esp)
     8048410:       89 54 24 04             mov    %edx,0x4(%esp)
     8048414:       e8 17 00 00 00          call   8048430 <__divdi3>
     8048419:       89 44 24 18             mov    %eax,0x18(%esp)
     804841d:       89 54 24 1c             mov    %edx,0x1c(%esp)
     8048421:       8b 44 24 18             mov    0x18(%esp),%eax
     8048425:       c9                      leave
     8048426:       c3                      ret

Заметка 8048414: call 8048430 <__divdi3>,

Я не могу использовать gcc lib для моего проекта, и он мультиплатформенный. Я надеялся не писать все __* функции для всех платформ (скорость не имеет значения), но теперь я немного запутался.

Может кто-нибудь объяснить, почему там __divdi3 (не __divti3) вызов создан для long long int (64-битное) разделение?

1 ответ

Решение

Нет слова как слова. На компьютерах с архитектурой x86 слово обычно означает 16 бит. Это принято. Как правило, word 16-битное или 32-битное число, ширина которого зависит от активированного режима (действительного или защищенного).

Я думаю, что эта терминология была заявлена, потому что linux/unix обычно работает на многих платформах. Вы можете почувствовать конфликты значений терминов на других инструментах. Живой пример gdb, который использует w для 32-битного слова и hw для 16-битного "полуслова".

РЕДАКТИРОВАТЬ: есть другое наименование, используемое для размера чисел с плавающей точкой, но иногда оно также используется для целых чисел. Это:

  • s - одиночное (точность, слово?) для четырехбайтовых целых чисел (int) / поплавки (float)
  • d - double (точность) для восьмибайтовых целых чисел (long или же long long) / поплавки (double)
  • t - десять байтов для целых чисел (long long) / поплавки (long double)

Это наименование используется для всех арифметических дополнений, таких как __divsi3, __divdi3, __divti3 или же __mulsi3, __muldi3, __multi3... (и все u - без знака - варианты). Вот причина __divdi3, Полный список на этой странице.

Разделение 64-битных чисел на 32-битных машинах использует сложный (и немного сложный) алгоритм. Вы можете использовать алгоритм принципа, который вы изучили в школе. Вычитание небольшого значения из большого числа будет тратить время, но вы можете вычитать детали с разным возведением в степень отдельно и быстрее получать результат. Вот простой псевдокод для этого (посмотрите на этот ответ о больших целых числах):

result = 0;
count = 0;
remainder = numerator;

while(highest_bit_of_divisor_not_set) {
    divisor = divisor << 1;
    count++;
}
while(remainder != 0) {
    if(remainder >= divisor) {
        remainder = remainder - divisor;
        result = result | (1 << count);
    }
    if(count == 0) {
        break;
    }
    divisor = divisor >> 1;
    count--;
}
Другие вопросы по тегам