Мы переместили проверку STRLENGHT = 0 и комментарий //IF STRLENGHT > 0 также должен быть перемещен. После встраивания функции стало возможным избавиться от копирования ESI в этих строках.
mov eax,esi
//*************
test eax,eax
jz @Else1Begin
mov eax,[eax-$04]
Последние строки переписывают EAX и последнее использованное значение в EAX, которое было скопировано из ESI.
mov eax,esi
//*************
//test eax,eax
test esi,esi
jz @Else1Begin
//mov eax,[eax-$04]
mov eax,[esi-$04]
В действительности мы должны также посмотреть в точку возможного перехода Else1Begin и увидим, что значение из EAX также используется здесь. Мы видим, что значение в EAX сразу обнуляется в следующей за меткой строке и поэтому не используется. Так что первая строка кажется лишняя и должна быть удалена.
Code: |
//mov eax,esi test esi,esi jz @Else1Begin mov eax,[esi-$04]
function CharPos19(Chr : Char; const Str : AnsiString) : Cardinal; asm push ebx push esi mov esi,edx mov ebx,eax //if StrLenght > 0 then test esi,esi jz @Else1Begin //StrLenght := Length(Str); //mov eax,[esi-$04] mov edx,[esi-$04] //mov edx,eax //I := 0; xor eax,eax //repeat @RepeatBegin : //Inc(I); inc eax //until((Str[I] = Chr) or (I > StrLenght)); cmp bl,[esi+eax-$01] jz @If2 cmp edx,eax jnl @RepeatBegin //if I <= StrLenght then @If2 : cmp edx,eax jnl @Exit //Result := I //else //Result := 0; xor eax,eax pop esi pop ebx ret //else //Result := 0; @Else1Begin : xor eax,eax @Exit : pop esi pop ebx end; |
Как результат встраивания функции LStrLen мы можем также удалить одну инструкцию. Функция LStrLen возвращает свой результат в EAX, затем он копируется в EDX. MOV EAX, [ESI-$04]. Это можно изменить на MOV EDX, [ESI-$04], а инструкцию MOV EDX, EAX можно удалить.
После этого изменения сменим наш фокус на цикл. Это особенно важно, поскольку это выполняется множество раз, в зависимости от длины строки и позиции, в которой произойдет сравнение.
Code: |
function CharPos20(Chr : Char; const Str : AnsiString) : Cardinal; asm push ebx push esi mov esi,edx mov ebx,eax //if StrLenght > 0 then test esi,esi jz @Else1Begin //StrLenght := Length(Str); mov edx,[esi-$04] //I := 0; xor eax,eax dec esi @RepeatBegin : //Inc(I); inc eax //until((Str[I] = Chr) or (I > StrLenght)); //cmp bl,[esi+eax-$01] cmp bl,[esi+eax] jz @If2 cmp edx,eax jnl @RepeatBegin //if I <= StrLenght then @If2 : cmp edx,eax jnl @Exit //Result := 0; xor eax,eax pop esi pop ebx ret //Result := 0; @Else1Begin : xor eax,eax @Exit : pop esi pop ebx end; |
Когда мы проанализируем код, то мы увидим, что здесь есть смещение -1 при адресации строки. Нет необходимости вычитать это смещение при каждой итерации. Будет хорошо, если мы один раз уменьшим указатель на Str в ESI до начала цикла. Мы также можем уменьшить счетчик цикла в EAX, но затем мы должны будем увеличить его на единицу при возврате результата.
В самом верху функции два входных параметра копируются в новые регистры. Это излишне и мы должны избавиться от лишнего копирования из обеих, но регистр EAX как счетчик цикла и мы сначала должны найти другой регистр для этой цели.
Code: |
function CharPos22(Chr : Char; const Str : AnsiString) : Cardinal; asm push ebx push esi mov esi,edx mov ebx,eax //if StrLenght > 0 then test esi,esi jz @Else1Begin //StrLenght := Length(Str); mov edx,[esi-$04] //I := 0; //xor eax,eax xor ecx,ecx dec esi @RepeatBegin : //Inc(I); //inc eax inc ecx //until((Str[I] = Chr) or (I > StrLenght)); //cmp bl,[esi+eax] cmp bl,[esi+ecx] jz @If2 //cmp edx,eax cmp edx,ecx jnl @RepeatBegin //if I <= StrLenght then @If2 : //cmp edx,eax cmp edx,ecx jnl @Exit //Result := 0; xor eax,eax pop esi pop ebx ret //Result := 0; @Else1Begin : xor eax,eax pop esi //New pop ebx //New ret //New @Exit : mov eax, ecx pop esi pop ebx end; |
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!