Мне не хочется углубляться в детали. Но оптимизация совсем нетривиальная штука. Если удалось избежать какого-то действия, это еще не значит, что код отработает быстрее.
Например, какой из двух кодов отработает быстрее в случае совпадения указателей (считаем, что memcpy такой же проверки внутри не делает, а просто тупо копирует):
void copy( void* ptr1, const void* ptr2, unsigned size )
{
if( ptr1 != ptr2 ) memcpy( ptr1, ptr2, size );
}
или:
void copy( void* ptr1, const void* ptr2, unsigned size )
{
memcpy( ptr1, ptr2, size );
}
Казалось бы первый? Ведь он не делает копирования в случае совпадения. Ан нет. Потому что он делает кое что похуже копирования - сравнение. Если бранч предскажется неправильно, то процессору придется очищать конвейр и нагружать заново.
А во втором случае он просто пробежит, скопирует из кеша в кеш какие-то данные, и уйдет на все, буквально десяток тактов.
Особенно учитывая, что правильный memcpy будет задействовать векторные регистры и векторный же конвейер. То есть, код копирования с большой вероятностью побежит параллельно с тем, что делается дальше.
У микрософта есть, кстати, очень правильный tool к xbox. Визуально показывает, как команды бегут через конвейры. Ему скармливаешь ассемблер, а он показывает, как это отработает. Очень помогает в оптимизации. А главное, зрелище совершенно завораживающее
