Деление 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--;
}