Такое поведение связано с тем, как лязг обрабатывает предварительно декремент в отличие от двоичных операторов, таких как под-и-назначение. Обратите внимание, что я просто попытаюсь объяснить на уровне clang, почему вы видите это поведение. Я не знаю, почему это было выбрано таким образом, но я предполагаю, что это было просто для удобства реализации.
Все функции, ссылки на которые приведены здесь, можно найти в классе ScalarExprEmitter
внутри lib/CodeGen/CGExprScalar.cpp
.
до/после декремента/инкремента все обработаны таким же образом, с помощью функции EmitScalarPrePostIncDec
: AN LLVM add
инструкция испускается либо 1
или -1
в качестве второго аргумента, в зависимости от экспрессии являющегося приращение или декремент соответственно.
Поэтому
--x
будет в конечном итоге, в LLVM IR, как что-то вроде
add i32 %x, -1
, которые, вполне естественно, переводит к x86 как что-то вроде
add $0xffffffff, %ecx
С другой стороны, двоичные операторы обрабатываются по-разному. В вашем случае,
x -= 1
будут обработаны EmitCompoundAssign
, которые в свою очередь вызывает EmitSub
. Будет испускаться что-то вроде следующих LLVM IR:
sub i32 %x, 1
Это, вероятно, только реализация и может измениться с уровнем оптимизации. Более интересно то, что он не использует 'dec', что может быть оптимизацией, потому что' dec' не изменяет столько флагов состояния, что это зависит от предыдущих инструкций. – ughoavgfhw
gcc производит тот же код для 'x -' и 'x = -1', используя' subl'. Интересно, что он использует 'xorl', если я включаю' -O3'. –
Нет никакого преимущества, и нет недостатка. Оба имеют 3 байта и имеют одинаковые характеристики производительности. – harold