- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
program Project1;
Var
i,j : Integer;
begin
i := 300001; j := 300002;
asm
MOV EAX, I;
XCHG EAX,j
MOV I, EAX;
end;
Write(i,' ',j); Readln;
end.
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+90
program Project1;
Var
i,j : Integer;
begin
i := 300001; j := 300002;
asm
MOV EAX, I;
XCHG EAX,j
MOV I, EAX;
end;
Write(i,' ',j); Readln;
end.
Ещё один кулхацкерный метод перестановки значений двух чисел местами.
Компилятор заменит XCHG EAX,j как-то так:
Соответственно весь код ,будет выглядеть примерно как:
Компилятор не будет ничего заменять. Раз уж программист написал в асмовставке xchg - значит так тому и быть. Если я не прав - пруфлинк в студию.
А если не выябываться с асмовставками, и написать tmp=x; x=y; y=tmp;, то при удачных обстоятельствах (к примеру свопают 2 локальных переменных и не в цикле), то компилятор вообще избавится от этого шлака, и вообще не будет генерить для него асм. А в самом неудачном случае да, получится твой нижний код.
Обоснуйте!
Как выше правильно заметил LispGovno, xchg имеет неявный lock префикс, в случаях, если одним из операндов является память. If a memory operand is referenced, the processor’s locking protocol is automatically implemented for the duration of the exchange operation, regardless of the presence or absence of the LOCK prefix or of the value of the IOPL. (IA-32 Intel Architecture, том 2) Поэтому компилятор не имеет права поменять xchg eax, j в асмовставке на mov ebx, j; mov j, eax; mov eax, ebx.
Да и вообще - зачем компилятору менять содержимое асмовставки? В конце концов программист ее не от хорошей жизни писал.
То я высказывался по поводу требований пруфлинка от возражателей. Ведь доказывать должен тот, кто утверждает, а не тот, кто отрицает (Дигесты и Кодекс Юстиниана, книга 22, титул 3, правило 2, http://www.e-reading.org.ua/chapter.php/21741/258/Dushenko_-_Mysli_i_izrecheniya_drevnih_s_ukazaniem _istochnika.html)
Так что правило "Ведь доказывать должен тот, кто утверждает, а не тот, кто отрицает" я не нарушал :P
Да, точно так же, как он избавляется от ненужных переменных, временных переменных, присваиваний одной и той же переменной два раза подряд и т.п.
На этом этапе компилятор еще не задумывается о ячейках памяти и регистрах. Лучше всего представить это как набор виртуальных регистров, по одному на каждый промежуточный результат. Причем если результат протащили через 30 переменных, он все равно останется в одном виртуальном регистре.
А вот ближе к концу компиляции он займется распределением настоящих регистров, и выделением ячеек в стеке под те виртуальные регистры, которые не помещаются в физические. Несколько виртуальных регистров могут попасть в одну ячейку стека или один и тот же регистр, если, конечно, они не требуются одновременно.
Поэтому у качественного оптимизирующего компилятора переменные в стеке и регистры имеют мало общего с переменными в исходном коде...
P.S. swap с кучей и глобальными переменными ему так искоренить не удастся, лучше всего оптимизируются именно локальные переменные.
Я понял. То есть переменные в коде - это смысловое разграничение данных, а результирующее разграничение по памяти и регистрам - физическое, направленное на оптимальность.
Вы читали что-то по компиляторам, кроме документации к конктретным продуктам? Кнут вроде ещё не сваял свой томик. Дайте линков?
В основном как раз документацию по LLVM и GCC, специализированных книг по компилерам не читал, т.к. свой пока писать не собираюсь...
Лол, как ты мои слова извратил, тролль. Я тебе сказал, как-бы поступил компилятор на месте программиста. Сказал, что он в целях оптимизации без нужды выставлять #LOCK не будет на строчку кеша или шину в многоядерной среде.
Реквестирую в тред Тараса.
Зачем компилятор генерит код, что-то держащий в регистрах? Да только ради эффективности, чтобы каждый раз не дергать их из оперативки.
В случае с асмовставкой ему придется от такой идеи отказаться (асмовставка может очень-очень косвенным путем потрогать и изменить переменную в стеке), и по-честному поместить переменную в стек, а после асмовставки, если ему вновь понадобится эта переменная, заново ее загрузить в регистр.
Имхо паскаль использует именно этот не самый эффективный, зато очень надежный способ (раз у него нет тонкой настройки попорченных регистров, как в gcc).
Ведь в ГК2.0 будет превью?