знак на ассемблере
Feb. 27th, 2008 11:33 am(эта запись будет интересна только программистам)
Расс Кокс рассказывает о супероптимизации - технике поиска самого быстрого куска кода путем полного перебора инструкций процессора (конечно, это работает только для очень коротких кусков кода). Любопытный пример там - самое быстрое воплощение функции знака (-1, 0 или 1 в зависимости от знака аргумента) на ассемблере 80x86. До такого вручную действительно додуматься нелегко:
cwd
neg ax
adc dx, dx
Здесь начальный аргумент лежит в ax, значение помещается в dx. Работает следующим образом: сначала cwd расширяет знак ax в dx, после чего в dx лежит -1, если аргумент отрицательный, а иначе 0. neg ax меняет знак ax, но это на самом деле неважно, а важно то, что эта инструкция помещает в флаг carry единицу, только если аргумент был ненулевой.
Наконец adc dx, dx складывает dx с самим собой, добавляет carry от второй инструкции, и помещает результат в dx. В результате выходит:
- если ax<0, то dx вначале -1, carry равен 1, результат равен -1*2+1 = -1 (во как!)
- если аx=0, то dx вначале 0, carry равен 0, результат 0*2+0=0
- если ax>0, то dx вначале 0, carry равен 1, результат 0*2+1=1
Красиво!
Расс Кокс рассказывает о супероптимизации - технике поиска самого быстрого куска кода путем полного перебора инструкций процессора (конечно, это работает только для очень коротких кусков кода). Любопытный пример там - самое быстрое воплощение функции знака (-1, 0 или 1 в зависимости от знака аргумента) на ассемблере 80x86. До такого вручную действительно додуматься нелегко:
cwd
neg ax
adc dx, dx
Здесь начальный аргумент лежит в ax, значение помещается в dx. Работает следующим образом: сначала cwd расширяет знак ax в dx, после чего в dx лежит -1, если аргумент отрицательный, а иначе 0. neg ax меняет знак ax, но это на самом деле неважно, а важно то, что эта инструкция помещает в флаг carry единицу, только если аргумент был ненулевой.
Наконец adc dx, dx складывает dx с самим собой, добавляет carry от второй инструкции, и помещает результат в dx. В результате выходит:
- если ax<0, то dx вначале -1, carry равен 1, результат равен -1*2+1 = -1 (во как!)
- если аx=0, то dx вначале 0, carry равен 0, результат 0*2+0=0
- если ax>0, то dx вначале 0, carry равен 1, результат 0*2+1=1
Красиво!
no subject
Date: 2008-02-27 09:45 am (UTC)no subject
Date: 2008-02-27 09:56 am (UTC)no subject
Date: 2008-02-27 10:08 am (UTC)который понятно немножечко прибивает конвейер
no subject
Date: 2008-02-27 10:23 am (UTC)no subject
Date: 2008-02-27 10:30 am (UTC)no subject
Date: 2008-02-27 10:58 am (UTC)no subject
Date: 2008-02-27 11:09 am (UTC)Но можно вместо сдвига какую-нибудь маску использовать наверное. Если предполагать, что знак находится в старшем разряде.
no subject
Date: 2008-02-27 12:23 pm (UTC)no subject
Date: 2008-02-27 09:05 pm (UTC)Мне казалось, что знак копируется для signed и стирается для unsigned.
На msvc и gcc это точно так:
signed int x = ffffff85;
x>>2 = ffffffe1
unsigned int y = ffffff85;
y>>2 = 3fffffe1
no subject
Date: 2008-02-27 09:24 pm (UTC)The Committee has affirmed the freedom in implementation granted by the Base Document in not requiring the signed right shift operation to sign extend, since such a requirement might slow down fast code and since the usefulness of sign extended shifts is marginal.
no subject
Date: 2008-02-27 09:39 pm (UTC)Ни фига себе заява =) Инструкцию SAR в процессор, оказывается, просто так пихнули.
А по поводу shift-а таки действительно:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2^E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
ISO/IEC 9899:TC3
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
no subject
Date: 2008-03-02 06:09 pm (UTC)Сейчас при повышенной стоимости условных переходов (неизвестно, предвыборку какого кода делать) предпочитают в подобных случаях, даже при том же сравнении, использовать операции типа setc, setn, которые хоть и условные, но гарантированно чего-то кладут в регистр.
Ну а приём из исходного постинга - это уже случайное чудо:), но проще их всех.
no subject
Date: 2008-02-27 10:13 am (UTC)Но очень процессор-специфично, под каждую платформу супероптимизация будет своя. Основной вопрос - в каких случаях поиск значительного количества таких трюков (всё-таки, полуавтоматический) будет оправдан при разработке компиляторов?
no subject
Date: 2008-02-27 10:17 am (UTC)если придумать сотню таких хинтов, каждый из которых даёт +0.3% к производительности -- то простой арифметикой получаем +30%, что уже неплохо ;)
no subject
Date: 2008-02-27 10:24 am (UTC)На самом деле в таком прекрасном случае +142%.
no subject
Date: 2008-02-27 10:26 am (UTC)no subject
Date: 2008-02-27 10:28 am (UTC)no subject
Date: 2008-02-27 10:25 am (UTC)no subject
Date: 2008-02-27 10:29 am (UTC)при том что мало того, что возводить надо в 100-ю степень, так ещё и надо это делать с числом 1.003
мистика
no subject
Date: 2008-02-27 10:36 am (UTC)no subject
Date: 2008-02-27 06:34 pm (UTC)no subject
Date: 2008-02-27 10:21 am (UTC)no subject
Date: 2008-02-27 06:29 pm (UTC)no subject
Date: 2008-02-27 11:08 am (UTC)no subject
Date: 2008-02-27 12:56 pm (UTC)особенно - "додуматься вручную" :)
no subject
Date: 2008-02-27 01:09 pm (UTC)Хотя конечно, для оптимизации кода можно и не так вы..вернуться, все равно его читать никто не будет.
no subject
Date: 2008-02-27 06:30 pm (UTC)a^=b^=a^=b, то увы, это незаконно, поскольку есть два присваивания а без sequence point между ними.
no subject
Date: 2008-02-27 09:29 pm (UTC)это абсолютно легальный С/С++, эквивалентный
a^=(b^=(a^=b))
Оператор a=^b возвращает новое значение a. Никаких альтернативных порядков выполнения тут нет.
no subject
Date: 2008-02-27 09:38 pm (UTC)t1 = a ^ b;
t2 = b ^ t1;
t3 = a ^ t2;
a = t1;
b = t2;
a = t3;
Т.к. sequence points нет, то порядок двух присваиваний a не определен. Оптимизирующий компилятор вправе выбросить любое из двух. Это не означает, что существует хоть один, который выбрасывает "нужное", но тем не менее.
no subject
Date: 2008-02-27 01:46 pm (UTC)no subject
Date: 2008-02-27 03:33 pm (UTC)no subject
Date: 2008-02-27 03:36 pm (UTC)no subject
Date: 2008-02-27 04:15 pm (UTC)no subject
Date: 2008-02-27 04:40 pm (UTC)no subject
Date: 2008-02-27 06:37 pm (UTC)no subject
Date: 2008-02-27 09:55 pm (UTC)xor ax, ax
"В этих случаях нельзя использовать общие методики оптимизации."
http://www.wasm.ru/article.php?article=1010002
no subject
Date: 2008-02-28 02:36 am (UTC)- тут много подобных приёмчиков
В частности для вычисления знака:
sign = +1 | (v >> (sizeof(int) * 8 - 1));
no subject
Date: 2008-02-28 03:24 am (UTC)no subject
Date: 2008-03-05 05:52 pm (UTC)no subject
Date: 2008-03-11 11:01 am (UTC)