Постинкремент в доходах: как они реализованы?

Итак, я знаю, что многие языки в стиле C имеют операторы декремента (--) и инкремента (++) и позволяют выполнять мутацию до или после вычисления всего выражения.

Что происходит, когда пост-инкремент происходит при возврате? Я не спрашиваю с точки зрения поведения, а скорее реализации.

Учитывая виртуальную машину (например, JavaScript/JVM) или физическую машину (например, скомпилированную C++), являются ли сгенерированные коды операций чем-то вроде следующего? (Предполагая аргументы/возвраты на основе стека.)

int x = 4, y = 8;
return f(++a) + y++;

Превращается в это: (Может быть?)

LOAD 4 A
LOAD 8 B

INC A
PUSH A
CALL F
POP INTO C
ADD C BY B
INC B
RET C

Если да, то как такие операции в этих языках решают, куда встроить приращение, когда выражение становится сложным, возможно, даже немного Lispish?


person Louis Jackman    schedule 17.03.2013    source источник
comment
Я думаю, что INC Bи ADD C BY B следует поменять местами, приращение к y следует применять после суммы. Кроме того, если y является локальной переменной, не будет ли приращение поста к y мертвым кодом?   -  person Jorge Núñez    schedule 17.03.2013
comment
Фиксированный. Но куда он пойдет в сложном выражении? Сразу после того же?   -  person Louis Jackman    schedule 17.03.2013
comment
Это зависит от реализации, например, в таком выражении, как (x++ + y++) - z++ в С++, в спецификации нет ничего, что говорило бы, в каком порядке должны выполняться приращения поста, он будет оценивать сумму, вычитание, а затем он мог бы оценить пост увеличивается в любом порядке, который он хочет, или он может даже оценить x++ после добавления точно так же.   -  person Jorge Núñez    schedule 17.03.2013
comment
Да, раньше я не увлекался присваиваниями-выражениями, но это только усугубляло ситуацию...   -  person Louis Jackman    schedule 17.03.2013


Ответы (3)


После оптимизации кода (либо компилятором C++, либо JIT-компилятором) я ожидаю нечто похожее на следующее:

Источник:

int x = 4, y = 8;
return f(++x) + y++;

Инструкции:

PUSH 5
CALL f
POP INTO A
ADD 8 to A
RET A

Инструкции, которые я перечислил, верны (если только я не допустил какой-нибудь глупой ошибки), и они требуют только преобразований кода, которые, как я знаю, способны выполнить оптимизаторы. Обычно неиспользуемые результаты не рассчитываются, а операции с известными результатами рассчитываются во время оптимизации.

Вполне возможно, что в конкретной архитектуре есть более эффективный способ сделать это, и в этом случае есть большая вероятность, что оптимизатор узнает об этом и использует его. Оптимизаторы часто превосходят мои ожидания, так как я не являюсь опытным программистом на ассемблере. В этом случае вполне вероятно, что соглашение о вызовах диктует одно и то же место для возвращаемого значения в случае функции f и этого кода. Таким образом, может не быть необходимости в каком-либо POP - к местоположению регистра возврата/стека может быть просто добавлено 8. Кроме того, если функция f встроена, оптимизация будет применена после встраивания.

Так, например, если f возвращает input * 2, тогда вся функция может оптимизироваться до:

RET 18
person Steve Jessop    schedule 17.03.2013
comment
Да, реалистичный набор инструкций имеет много тонкостей; может оказаться, что существует специально оптимизированная инструкция, которая встраивает константу до 127 в код операции, и более выгодно использовать эту встроенную константу, а затем увеличивать ее еще несколько раз, чтобы получить число, и так далее. В наши дни на этом уровне можно получить очень мало полезной информации, если только вы не занимаетесь реализацией оптимизирующих компиляторов. - person Marko Topolnik; 17.03.2013
comment
@MarkoTopolnik: действительно, читая разборку, вы можете подумать, хм, это кажется несколько окольным способом добавления 129, но я предполагаю, что это наиболее эффективный, но пока он узнаваемо добавляет 129, вы не обращаете внимания. В более сложных функциях оптимизаторы находят действительно умные способы объединения нескольких операций, и это может стать немного интереснее. Но пока вы доверяете оптимизатору, обычно важно, какой код он генерирует :-) - person Steve Jessop; 17.03.2013
comment
Вот прекрасный доклад Гая Стила, в котором он подробно описывает -оптимизация, которую он и его поколение программистов делали регулярно. Современные оптимизаторы не настолько умны, но я думаю, что общий беспорядок, который получается, сравним :) - person Marko Topolnik; 17.03.2013

Среда выполнения Java очень далека от вашего исходного кода и даже от байт-кода. После JIT-компиляции метода результирующий машинный код агрессивно оптимизируется. Но что еще более важно, детали этой оптимизации выходят далеко за рамки любой спецификации. Если вас это интересует, вы можете углубиться в реализацию, такую ​​как HotSpot, но все, что вы узнаете из нее, будет зависеть от платформы, версии, номера сборки, аргументов запуска JVM и даже отдельного запуска JVM.

person Marko Topolnik    schedule 17.03.2013