Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a compiler to generate adc instruction

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.)

like image 828
cooky451 Avatar asked Jun 28 '13 18:06

cooky451


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.

like image 120
fuz Avatar answered Nov 15 '22 17:11

fuz


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
like image 36
sh1 Avatar answered Nov 15 '22 17:11

sh1


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.

like image 1
Sam Harwell Avatar answered Nov 15 '22 17:11

Sam Harwell