Is there any way to get either Clang, GCC or VS to generate adc (add with carry) instructions only using Standard-C++(98/11/14)? (Edit: I mean in x64 mode, sorry if that wasn't clear.)
-
those are `c` compilers – tay10r Jun 28 '13 at 18:48
-
6@Taylor: "GCC" and "Visual Studio" are the names of compiler collections, which contain C++ compilers among others. `clang` is a C++ compiler. – Ben Voigt Jun 28 '13 at 18:50
-
@BenVoigt oh, then I guess that makes sense. – tay10r Jun 28 '13 at 18:51
-
FWIW, In x64, I've *never* been able to get any compiler to generate `adc` without inline assembly. – Mysticial Jun 28 '13 at 18:55
-
2Is there any particular reason you want to do this? – Oliver Charlesworth Jun 28 '13 at 18:56
-
You can play around with the gcc explorer, maybe that will get you somewhere. – PlasmaHH Jun 28 '13 at 19:03
-
3The whole point of C or C++ is to isolate the programmer from platform-specific assembly. The C or C++ standards don't ever mention ADC (which is an implementation detail) so the answer is **no**. There's no guarantee that a particular processor provides an ADC instruction... – syam Jun 28 '13 at 19:03
-
A definite no. *but*, there might be compiler extensions that are likely to yield one, e.g., clang's [__builtin_addc](http://clang.llvm.org/docs/LanguageExtensions.html#builtin-functions) functions. – Brett Hale Jun 28 '13 at 19:56
-
@syam I never wanted a guarantee. I'm just looking for code examples which include enough hints for the optimizer to generate an adc instruction. – cooky451 Jun 28 '13 at 20:07
-
1@OliCharlesworth Yes, I'd like to implement efficient arbitrary precision arithmetic in ISO-C++, but I don't think it's possible at the moment. – cooky451 Jun 28 '13 at 20:08
-
The problem is also related to https://stackoverflow.com/questions/56101507/is-there-anything-special-about-1-0xffffffff-regarding-adc – Friedrich -- Слава Україні Sep 18 '19 at 15:15
-
The problem is also related to https://stackoverflow.com/questions/56101507/is-there-anything-special-about-1-0xffffffff-regarding-adc – Friedrich -- Слава Україні Sep 18 '19 at 15:17
3 Answers
If your code makes a comparison and adds the result of the comparison to something, then an adc
is typically emitted by gcc 5 (incidentally, gcc 4.8 does not emit an adc
here). For example,
unsigned foo(unsigned a, unsigned b, unsigned c, unsigned d)
{
return (a + b + (c < d));
}
assembles to
foo:
cmpl %ecx, %edx
movl %edi, %eax
adcl %esi, %eax
ret
However, it is a bit tricky to get gcc to really emit an adc
.

- 88,405
- 25
- 200
- 352
-
1Yup, it is hard to get gcc to emit `adc` for conditional increments like the above. I _think_ gcc has a peephole or other stage that takes an `adc` with a `0` immediate and turns into a (generally worse on modern hardware) `xor eax, eax; setb al; add ..., eax` sequence. For example, if you remove `b` from the above so it is `(a + (c < d))` the natural sequence would be to use an `adc` with `0` but gcc does the weird `setb` thing. Same for ternary expression like `a += (c < d) ? 1 : 0`. However, if you do `a += (c < d) ? 3 : 2` or any other off-by-one values it _does_ use `adc eax, 2`. – BeeOnRope Jul 17 '18 at 21:35
-
1So it seems only when `0` would be the immediate it does this weirdness. Also, if you use a branch, like `if (c < d) a++` it uses `adc`! I tried out [many examples on godbolt](https://godbolt.org/g/cGiU5p). – BeeOnRope Jul 17 '18 at 21:37
There's an __int128_t
type available on GCC for amd64 and other 64bit targets, which will use a pair of add
/adc
instructions for a simple addition. (See the Godbolt link below).
Also, this pure ISO C code may compile to an adc:
uint64_t adc(uint64_t a, uint64_t b)
{
a += b;
if (a < b) /* should simplify to nothing (setting carry is implicit in the add) */
a++; /* should simplify to adc r0, 0 */
return a;
}
For me (ARM) it generated something kind of silly, but it compiles for x86-64 (on the Godbolt compiler explorer) to this:
mov rax, rdi # a, a
add rax, rsi # a, b
adc rax, 0 # a,
ret

- 328,167
- 45
- 605
- 847

- 4,324
- 17
- 30
-
1I was going to add that I think `-funsafe-math-optimizations` might kill off that whole `if` block, but it doesn't seem to. I think C might allow such an optimisation, though, so look out there. – sh1 Jun 28 '13 at 23:17
-
2unsigned wraparound is well-defined in C/C++, as binary integer. It's guaranteed to work properly. `-funsafe-math-optimizations` only affects floating point behaviour. Maybe you're thinking of signed integer wraparound being undefined behaviour? `-fwrapv` makes it well-defined (as 2's complement), but is *not* enabled by default. – Peter Cordes Jun 29 '16 at 14:50
If you compile a 64-bit signed addition for X86 (int64_t
in C++ 11), the compiled code will contain an adc
instruction.
Edit: code sample:
int64_t add_numbers(int64_t x, int64_t y) {
return x + y;
}
On X86, the addition is implemented using an add
instruction followed by an adc
instruction. On X64, only a single add
instruction is used.

- 97,721
- 20
- 209
- 280
-
Can you give a minimal example function? I have never seen it in any of my binaries, only lea(q) and similar. – PlasmaHH Jun 28 '13 at 19:05
-
Please see my edit, I should have included this before. The background here is to see if it is possible to build efficient arbitrary integer arithmetic in Standard-C++. :) – cooky451 Jun 28 '13 at 20:06