Анимация
JavaScript
|
Главная Библионтека int i, n; double *X; double * Y; double DA; for (1=0; i<n; 1++] Y[i] = Y[i] - DA * X[i] Oh является ключевым участком при решении линейных уравнений (алгоритм DAXPY). DSIZE
результат Здесь используются те же методы, что и в примере пункта 6.25.1.5: четчик цикла в качестве индекса и последовательность отрицательных значений от -N до 0. Коней выполнения одной операции пересекается с началом выполнени другой. Смешение различных инструкций плавающей запятой работает прекрасно: задер** в 2 такта между FMUL и FSUBR заполняется FSTP предыдущего результата. Задерж в 3 такта между FSUBR и FSTP заполняется инструкциями управления циклом и первыми двумя инструкциями следующей итерации. Задержки AGI удалось избежать благода" чтению в первом такте после изменения индекса только тех параметров, которые о индекса не зависят. Это решение занимает 6 тактов на операцию! 6.25.1.11. Развертывание циклов с инструкциями с плавающей запятой (Р1 и PMl Цикл DAXPY, развернутый в 3 раза, довольно сложен: r3?.i.-..9."J."..V.lf." Э.Р?! семейства Pentium Пример DSIZE = 8 IF DSIZE EQ SHIFTCOUNT = ELSE SHIFTCOUNT = ENDIF MOV MOV SHL JZ MOV SUB MOV SUB SUB TEST FLD JNS FMUL FLD FMUL FXCH FSUBR FXCH FLD FMUL FXCH FSUBR FXCH FSTP FSUBR FXCH FSTP FLD FXCH FSTP ADD JS FMUL FSUBR SUB JZ FLD FMUL FXCH FSTP размер данных ; количество элементов ; погрешность счетчика ; DSIZE*N ; N = О ; указатель на X ; (3-N)*DSIZE ; указатель на Y конец указателя - погрешнос ; первый x ; меньше чем 4 операции еах, [N] есх, 3*dsize еах, shiftcount L4 esi, [x] есх, еах edi, [Y] esi, есх edi, есх есх, есх dsize ptr [esi+ecx] short L2 dsize ptr [da] dsize ptr [esi+ecx+dsize] dsize ptr [da] dsize ptr (edi+ecxj dsize ptr [esi+ecx+2*dsize; dsize ptr [da] DSIZE PTR [EDl+ECX+DSIZE] ST(2) DSIZE PTR [EDI+ECX] DSIZE PTR [EDI+ECX+2*DSIZE] DSIZE PTR [EDI+ECX+DSIZE] DSIZE PTR [ESI+ECX+3*DSIZE] DSIZE PTR [EDI+ECX+2*DSIZE] ECX, 3*DSIZE LI DSIZE PTR [DA] DSIZE PTR [EDI+ECX] ECX, 2*DSIZE .; изменяем погрешность указатех SHORT L3 ; закончили DSIZE PTR [DA] ; начинаем новую операцию DSIZE PTR [ESI+ECX+3*DSIZE] ; цикл ; завершаем оставшуюся операц dsize PTR [edi+ecx+2*dsize] 438 Ассемблер в задачах защиты uнфopмaцj,
закончили L3: L4: Причина, по которой рассматривается вопрос, как развернуть цикл в три раза, не в том, чтобы порекомендовать подобный подход, а в том, чтобы продемонстрровать, как это сложно! Нужно быть готовым провести значительное количество времени, отлаживая и проверяя код со степенью развертывания меньше 4. Есть несколько проблем, о которых нужно позаботиться: в большинстве случаев невозможно устранить все задержки в цикле с инструкциями плавающей запятой, если только не свернуть его (т. е. в конце цикла будут операции, выполнение которых закончится в конце следующего повторения). Последний FLD в основном цикле примера является началом первой операции в следующей итерации. Неплохо сделать реализацию, с методикой пунктов 6.25.1.8 и 6.25.1.9, но это не рекомендуется делать с инструкциями плавающей запятой, потому что чтение дополнительного значения за границой массива может сгенерировать исключение ненормализованного операнда, если после массива не находится число с плавающей запятой. Чтобы избежать этого, приходиться делать по крайней мере на одну операцию больше после основного цикла. Количество операций, которое необходимо выполнить снаружи развернутого цикла, как правило, будет равно N MODULE R, где N - количество операций, а R - коэффициент развернутости цикла. Но в случае со свернутым циклом, нужно сделать на одну операцию больше, то есть (N-1) MODULO R + 1 в силу вышеуказанных причин. Обычно подготовительные операции выполняются до основного цикла, но здесь необходимо делать их позже в силу двух причин: одна причина - это забота об оставшемся операнде (из-за свертывания). Другая причина состоит в том, что вычисление количества дополнительных операций требует деления, если R не является степенью 2-n а деление занимает много времени. Дополнительные операции после основного п№ решают эту проблему. Другая задача - это высчитать, как влиять на счетчик цикла, чтобы он изменил знак в пра-вильный момент, и привести в порядок базовые указатели. Наконец, следует убедиться, чт" оставшийся от свертьшания операнд был обработан верно для всех значений N. Эпилоговый код, делающий 1 - 3 операции, можно организовать как отдельный чик-т но при этом появится неправильное предсказание, поэтому решение представленное вЫ ше быстрее. Теперь рассмотрим, насколько проще разворачивать цикл на 4 операции. £"....4:.19 процессоров семейства Pentium DSIZE = 8 MOV MOV MOV XOR LEA SUB LEA TEST JZ FLD FMUL FSUBR INC FSTP TEST JZ FLD FMUL FLD FMUL FXCH FSUBR FXCH FSUBR FXCH FSTP FSTP ADD TEST JZ FLD FLD FMUL FLD FMUL FLD FMUL FXCH FSUBR FXCH FMUL FXCH FSUBR FXCH FSUBR ; размер данных ; количество элементов ; указатель на X ; указатель на Y ; указывает на конец X ; -N ; указывает на конец Y ; тестируем N на нечетност ; делаем нечетную операцик ЕАХ, [N] ESI, [X] EDI, [Y] ЕСХ, ЕСХ ESI, [ESI+DSIZE*EAX] ЕСХ, ЕАХ EDI, [EDI+DSI2E*EAX] AL, 1 SHORT LI DSIZE PTR [DA] DSIZE PTR [ESI+DSIZE*ECX] DSIZE PTR [EDI+DSIZE*ECX] ECX ; увеличиваем значение счетчи DSIZE PTR [EDI+DSIZE*ECX-DSIZE] AL,2 ; можно ли сделать еще 2 операции DSIZE PTR [DA] ; N MOD 4=2 или 3. Делаем еще д DSIZE PTR [ESI+DSIZE*ECX] DSIZE PTR [DA] DSIZE PTR [ESI+DSIZE*ECX+DSIZE] DSIZE PTR [EDI+DSIZE*ECX] DSIZE PTR [EDI+DSIZE*ECX+DSIZE] DSIZE PTR [EDI+DSIZE*ECX] DSIZE PTR [EDI+DSIZE*ECX+DSIZE] ECX, 2 ; счетчик не делится 4 ECX, ECX L4 ; больше операций нет DSIZE PTR [DA] DSIZE PTR [ESI+DSIZE*ECX] ST,ST(1) DSIZE PTR [ESI+DSIZE*ECX+DSIZE] ST,ST(2) DSIZE PTR [ESI+DSIZE*ECX+2*DSIZE] ST,ST(3) ST(2) DSIZE PTR [EDI+DSIZE*ECX] ST(3) DSIZE PTR [ESI+DSIZE*ECX+3*DSIZE] DSIZE PTR [EDI+DSIZE*ECX+DSIZE] ST(2) DSIZE PTR [EDI+DSIZE*ECX+2*DSIZE] 440 Ассемблер в задачах защиты информац
L4 : Обычно довольно легко добиться отсутствия задержек в Щ1кле, развернутом на 4 и нет нужды в свертывании последней операщ1И. Количество дополнительных операций, которые нужно сделать за пределами основного цикла равно N MODULO 4, что можно легко посчитать без деления, просто протестировав два младших бита в N. Дополнительные операции делаются до основного цикла, а не после, чтобы сделать обработку счетчика цикла проще. Недостаток развертывания циклов в том, что дополнительные операции, выполняемые- за пределами цикла медленнее из-за несовершенного пересечения и возможных неправильных предсказаний переходов, а потери при первой загрузке кода выше из-за возросшего размера кода. В качестве основной рекомендации, можно принять то, что если N велико или если сворачивание цикла без развертывания не может удалить некоторых задержек, следует развернуть критические целочисленные циклы в два раза, а {щклы с инструкциями плавающей запятой в 4 раза. 6.25.2. Циклы в РРго, Р2 и РЗ в предыдущей части раздела (6.25.1) описывалось, как использовать свертьгаание и развертывание циклов, чтобы улучшить спаривание в Р1 и РММХ. На РРго, Р2 и РЗ нет никакой причины делать это благодаря механизму переупорядочевания инструкиий-Но здесь есть другие проблемы, о которых надо заботиться, связанные с границами БДИ и задержкой чтения регистров. 6.25.2.1. Рассмотрим те же примеры, что и в первой части раздела 6.25: процедуру-которая считывает целые числа из массива, изменяет их знак, и сохраняет результаты в другой массив. На С эта процедура выглядела бы так: void ChangeSign (int * А, int * В, int N) int i ; for (i=0; i<N; B[i] = -A[i]; -ва б-..9."У.:!....?" процессоров семейства Pentium Ее ассемблерный вариант: ChangeSign PROC NEAR PUSH PUSH EQU EQU EQU MOV JECXZ MOV MOV CLD LODSD NEG STOSD LOOP POP POP RET ChangeSign LI ; L2 ; ESI EDI DWORD PTR [ESP-H2] DWORD PTR [ESP-H6] DWORD PTR [ESP-f20] ECX, [N] L2 ESI, [A] EDI, [B] ENDP Это выглядит как довольно красивое решение, но, естественно, не самое оптималь ное, потому что он использует инструкции LOOP, LODSD и STOSD, которые генериру ют много мопов. Одна итеращм цикла занимает 6 - 7 тактов, если все данные находятс в кэше первого уровня. Если избегать данных инструкций, получим: ALIGN L1:
len=2, p2rESIwEAX len=3, pOlrwESIwF len=2, pOlrwEAXwF len=2, p4rEAX, p3rEDI len=3, pOlrwEDIwF len=l, pOlrwECXwF len=2, plrF Комментарии интерпретируются следующим образом: инструкция MOV ЕАХ [ESI оаита длиной, генерирует один моп для порта 2, который читает ESI и пишет (пере овывает) в ЕАХ. Эта информация требуется для анализа возможных узких мест. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 [ 71 ] 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |