x86 addl vs subl

assembly, c, clang, compiler-construction, x86

Solution

This behavior has to do with the way clang handles pre-decrement as opposed to binary operators like sub-and-assign. Note that I will just try to explain, at the clang level, why you see this behavior. I don't know why it was chosen to implement it this way but I guess it was just for ease of implementation.

All functions I reference here can be found in class `ScalarExprEmitter` inside `lib/CodeGen/CGExprScalar.cpp`.

Pre/post decrement/increment are all handled the same way by the function `EmitScalarPrePostIncDec`: an LLVM `add` instruction is emitted with either `1` or `-1` as second argument, depending on the expression being an increment or a decrement respectively.

Therefore,

--x

will end up, in the LLVM IR, as something like

add i32 %x, -1

which, quite naturally, translates to x86 as something like

add $0xffffffff, %ecx

Binary operators, on the other hand, are all handled differently. In your case,

x -= 1

will be handled by `EmitCompoundAssign` which in turn calls `EmitSub`. Something like the following LLVM IR will be emitted:

sub i32 %x, 1

Problem

I just notice that Clang compiles this statement (without any optimization, of course): ``` --x; /* int x; */ ``` into: ``` addl $4294967295, %ecx ## imm = 0xFFFFFFFF ``` Why? Is there any advantage of using `addl` instead of the "obvious" `subl`? Or is it just an implementation fact? What tricks me is that this one: ``` x -= 1; ``` becomes: ``` subl $1, %eax ``` Clang info: ``` Apple clang version 3.0 (tags/Apple/clang-211.12) (based on LLVM 3.0svn) Target: x86_64-apple-darwin11.2.0 Thread model: posix ```

Original source