Оптимизация для процессоров семейства Pentium: 20. Цепочки зависимости (PPro, PII и PIII) — Архив WASM.RU
Серии инструкций, где выполнение каждой зависит от результата предыдущей, называется цепочкой зависимости. Большие цепочки нужно по возможности избегать, потому что они делают невозможным выполнение не по порядку и параллельное выполнение.
Пример:
Код (Text):
MOV EAX, [MEM1] ADD EAX, [MEM2] ADD EAX, [MEM3] ADD EAX, [MEM4] MOV [MEM5], EAXВ этом примере инструкция ADD генерирует 2 мопа, один для чтения из памяти (порт 2) и один для сложения (порт 0 или 1). Моп чтения может выполняться не по порядку, в то время как моп сложения дожна ждать, пока выполниться предыдущий моп. Эта цепочка зависимости занимает не очень много времени, так как каждое сложение требует только один такт. Но если в вашем коде содержатся медленные инструкции, такие как умножения, или еще хуже - деление, тогда вам определенно нужно сделать что-нибудь, чтобы убрать цепочку зависимости. Это можно сделать, используя разные приемники:
Код (Text):
MOV EAX, [MEM1] ; начало первой цепочки MOV EBX, [MEM2] ; начало второй цепочки с другим приемником IMUL EAX, [MEM3] IMUL EBX, [MEM4] IMUL EAX, EBX ; в конце соединяем цепочки MOV [MEM5], EAXЗдесь вторая инструкция IMUL может начаться до того, как будет завершено выполнение первой. Так как у инструкции IMUL вызывает задержку в 4 такта и полностью конвееризована, вы можете использовать до 4-х приемников.
Деление не конвееризовано, поэтому вы не можете делать то же самое со связанными делениями, но, разумеется, вы можете умножить все делители и сделать только одно деление в конце.
У инструкций с плавающей запятой более длинная задержка, чем у целочисленных инструкций, поэтому вам стоит разбивать слишком длинные цепочки связанных инструкций с плавающей запятой.
Код (Text):
FLD [MEM1] ; начинаем первую цепочку FLD [MEM2] ; начинаем вторую цепочку с другим приемником FADD [MEM3] FXCH FADD [MEM4] FXCH FADD [MEM5] FADD ; соединяем цепочки в конце FSTP [MEM6]Вам потребуется для этого много инструкций FXCH, но не беспокойтесь: они стоят дешево. Инструкции FXCH обрабатываются в RAT с помощью переименования регистров, поэтому они не создают никакой назгрузки на порты выполнения. Тем не менее, FXCH генерирует один моп в RAT, ROB и в станции вывода из обращения.
Если цепочка зависимости очень длиная, вам может потребоваться три приемника:
Код (Text):
FLD [MEM1] ; начинаем первую цепочку FLD [MEM2] ; начинаем вторую цепочку FLD [MEM3] ; начинаем третью цепочку FADD [MEM4] ; третья цепочка FXCH ST(1) FADD [MEM5] ; вторая цепочка FXCH ST(2) FADD [MEM6] ; первая цепочка FXCH ST(1) FADD [MEM7] ; третья цепочка FXCH ST(2) FADD [MEM8] ; вторая цепочка FXCH ST(1) FADD ; соединяем первую и третью цепочку FADD ; результат соединяем со второй цепочкой FSTP [MEM9]Избегайте сохранения промежуточных данных в памяти и немедленного их считывания:
Код (Text):
MOV [TEMP], EAX MOV EBX, [TEMP]Возникают потерю из-за попытки чтения из памяти до того, как завершена предыдущая запись туда же. В вышеприведенном примере измените последнюю инструкцию на 'MOV EBX, EAX' или поместите какие-нибудь инструкции между ними.
Есть одна ситуация, когда вы не сможете избежать сохранения промежуточных данных в памяти. Она возникает тогда, когда вы перемещаете данные из целочисленного регистра в регистр FPU или наоборот. Например:
Код (Text):
MOV EAX, [MEM1] ADD EAX, [MEM2] MOV [TEMP], EAX FILD [TEMP]Если вам нечего поместить между записью в TEMP и считыванием из него, вы можете использовать регистр плавающей запятой вместо EAX:
Код (Text):
FILD [MEM1] FIADD [MEM2]Последовательные переходы, вызовы или возвраты также можно считать цепочками зависимости. Производительность этих инструкций равна одному переходу за два такта. Поэтому рекомендуется загружать микропроцессор какой-нибудь полезной работой между переходами. © Агнер Фог, пер. Aquila
Оптимизация для процессоров семейства Pentium: 20. Цепочки зависимости (PPro, PII и PIII)
Дата публикации 22 авг 2002