General
В вашем обычном компиляторе сгенерированный код чаще всего будет таким же, по крайней мере, если предположить, что вы используете обычные
csc.exe /optimize+
cl.exe /O2
g++ -O2
и соответствующие режимы оптимизации по умолчанию.
Общая мантра: профиль, профиль, профиль (и не оптимизируйте микро, пока ваш профилировщик не скажет вам).Вы всегда можете посмотреть на сгенерированный код 2 , чтобы увидеть, есть ли возможности для улучшения.
Подумайте об этом так, например, код C #:
C # /.NET
Каждый из ваших complexExpressions является де-факто вызовом функции (call, calli, код операции callvirt 3 ), который требует, чтобы его аргументы были помещены в стек,Возвращаемое значение будет оставлено в стеке вместо параметров на выходе.
Теперь, CLR - это виртуальная машина, основанная на стеке (т. Е. Без регистра), это равнозначно анонимная временная переменная в стеке.Единственное различие заключается в количестве идентификаторов, используемых в коде.
Теперь то, что движок JIT делает с этим, другое дело: движок JIT должен будет переводить эти вызовы в собственную сборку и может выполнять оптимизацию путем настройкираспределение регистров, порядок команд, прогноз ветвлений и тому подобное 1
1 (хотя на практике для этого примера это не будет разрешеносделать более интересные оптимизации, потому что complex function calls
может иметь побочные эффекты, а спецификации C # очень четко указывают на порядок оценки и так называемую последовательность). Обратите внимание , однако, что движку JIT разрешено встроенных вызовов функций, чтобы уменьшить накладные расходы на вызовы.
Не только когда они не виртуальные, но (IIRC)также, когда тип среды выполнения может быть известен статически во время компиляции для определенных внутренних компонентов .NET Framework.Мне нужно было бы найти ссылку на это, но на самом деле я думаю, что в .NET Framework 4.0 есть атрибуты, которые явно предотвращают встраивание функций платформы;это позволяет Microsoft исправлять код библиотеки в пакетах обновления / обновления, даже если пользовательские сборки были заранее скомпилированы (ngen.exe) в собственные образы.
C / C ++
В C / C ++ модель памяти намного более слабая (т. Е. По крайней мере до C ++ 11), и код обычно компилируется до собственных инструкций ввремя компиляции напрямую.Добавим, что компиляторы C / C ++ обычно выполняют агрессивное встраивание, код даже в таких компиляторах обычно будет одинаковым, если только вы не компилируете без включенной оптимизации
2 Я использую
ildasm
или monodis
для просмотра сгенерированного кода IL mono -aot=full,static
или mkbundle
для создания собственных объектных модулей и objdump -CdS
для просмотра аннотированной собственной сборкиинструкции для этого.
Обратите внимание, что это просто любопытство, потому что редко бывает, что я нахожу интересные узкие места таким образом.Однако см. J в сообщениях Skeet в блоге об оптимизации производительности Noda.NET
для хороших примеров неожиданностей, которые могут скрываться в сгенерированном коде IL для общих классов.
3 Редактировать не точно для операторов встроенных функций компилятора, хотя даже они просто оставят свой результат в стеке.