Нечто похожее уже было, но "повторенье - мать ученья" 8) Есть структура состоящая из 4 байт: Код (Text): секунды db ? ;(0..59) младший байт минуты db ? ;(0..59) часы db ? ;(0..23) дни db ? ;(-128..127) старший байт Необходимо написать оптимизированные по размеру функции time_add и time_sub, принимающие в регистрах r1,r2 (выбираете произвольно, но должны совпадать для обеих функций) две такие структуры, и вычисляющие r1=r1+r2 и r1=r1-r2 соответственно. Код должен быть без переходов (за исключением ret'а в конце функции), r2 портить нельзя, секунды и минуты в результате не должны выходить за диапазон 0..59, а часы за диапазон 0..23. Примеры: 0F2828h(15:40:40) + 0F2828h(15:40:40) = 1071514h(1д 7:21:20) 0F2828h(15:40:40) - 1071514h(1д 7:21:20) = 0FF081314h (-1д 8:19:20)
Первое что приходит в голову (без претензий на "оптимальность") Код (Text): ;сложение: r1=eax, r2=edx mov ebx,0E8C4C4h add eax,ebx add eax,edx mov ecx,eax and ecx,C0C0C0h shr ecx,6 imul ecx,85 and ecx,ebx sub eax,ecx ;вычитание sub eax,edx mov ecx,eax and ecx,C0C0C0h shr ecx,6 imul ecx,85 and ecx,0E8C4C4h sub eax,ecx
leo - так вот он какой настоящий дзен! all У вас пока есть уникальный шанс улучшить данный код как минимум на 2-3 байта. Главное - правильно выбрать регистры.
Раз народ регистры выбирать не хочет, придётся это сделать самому. r1=ecx,r2=edx Сложение, 25 байт: Код (Text): mov ebx,$E8C4C4 add ecx,edx add ecx,ebx shld eax,ecx,26 and eax,$30303 imul eax,85 and eax,ebx sub ecx,eax Вычитание, 21 байт: Код (Text): sub ecx,edx shld eax,ecx,26 and eax,$30303 imul eax,85 and eax,$E8C4C4 sub ecx,eax
Вот наконец собрался приписать примечание насчет использования imul Разумеется ничего оригинального и дзенного в этом нет, т.к. mul\imul - это стандартный прием размножения или перестановки бит. Все становится ясно и понятно, если представить imul r,i в двоичном виде как сумму из N исходных чисел r, где N - число единичных бит в множителе i, а сдвиги задаются позициями этих бит в i. Например, в рассматриваемом случае мы имеем в каждом байте либо 0, либо 11b, из которых нужно сделать 0FFh. Это ес-но делается путем суммирования 4-х значений со сдвигом 0,2,4,6 бит Код (Text): хххххх00000011 ;=r*00000001 + хххх00000011.. ;=r*00000100 + хх00000011.... ;=r*00010000 + 00000011...... ;=r*01000000 ----------------------------- = хххххх11111111 ;=r*01010101b = imul r,85 Этот прием также можно использовать для упаковки (группировки), распаковки и подсчета установленных бит в байтах или тетрадах. Единственое что требуется это аккуратно расписать сдвиги и обеспечить отсутствие наложений, которые могут исказить результат (предварительный AND). Например, подсчитать кол-во байт в которых установлен младший бит можно так: Код (Text): ;and eax,1010101h imul eax,1010101h shr eax,24 Чтобы биты не суммировались, а собрались в кучку (сгруппировались) нужно, чтобы сдвиги в каждом слагаемом imul были не кратны 8 и шли с нарастанием или убыванием. Например, чтобы сгруппировать биты в инверсном порядке нужно умножить на число с возрастающими сдвигами 8040201h (+ shr 24), а для прямого порядка - на число с убывающими сдвигами 204081h (+ shr 21). Ес-но при желании можно расставить биты и в произвольном порядке. Аналогичным образом делается и обратная операция (распаковка) - выбираем сдвиги так, чтобы каждый бит байта встал на свою позицию в определенном байте, затем после imul делаем AND для обнуления мусора