Ответ 1
На самом деле gcc автоматически будет использовать перенос, если вы тщательно напишете свой код...
Я скомпилировал этот код с помощью gcc -O2 -Wall -Werror -S:
void increment128_1(unsigned long &hiWord, unsigned long &loWord)
{
    const unsigned long hiAdd=0x0000062DE49B5241;
    const unsigned long loAdd=0x85DC198BCDD714BA;
    loWord += loAdd;
    if (loWord < loAdd) ++hiWord; // test_and_add_carry                                                                                                             
    hiWord += hiAdd;
}
void increment128_2(unsigned long &hiWord, unsigned long &loWord)
{
    const unsigned long hiAdd=0x0000062DE49B5241;
    const unsigned long loAdd=0x85DC198BCDD714BA;
    loWord += loAdd;
    hiWord += hiAdd;
    hiWord += (loWord < loAdd); // test_and_add_carry                                                                                                               
}
Это сборка для increment128_1:
.cfi_startproc
        movabsq     $-8801131483544218438, %rax
        addq        (%rsi), %rax
        movabsq     $-8801131483544218439, %rdx
        cmpq        %rdx, %rax
        movq        %rax, (%rsi)
        ja  .L5
        movq        (%rdi), %rax
        addq        $1, %rax
.L3:
        movabsq     $6794178679361, %rdx
        addq        %rdx, %rax
        movq        %rax, (%rdi)
        ret
... и это сборка для increment128_2:
        movabsq     $-8801131483544218438, %rax
        addq        %rax, (%rsi)
        movabsq     $6794178679361, %rax
        addq        (%rdi), %rax
        movabsq     $-8801131483544218439, %rdx
        movq        %rax, (%rdi)
        cmpq        %rdx, (%rsi)
        setbe       %dl
        movzbl      %dl, %edx
        leaq        (%rdx,%rax), %rax
        movq        %rax, (%rdi)
        ret
Обратите внимание на отсутствие условных ветвей во второй версии.
[править]
Кроме того, ссылки часто неэффективны для производительности, потому что GCC должен беспокоиться об псевдониме... Часто бывает лучше просто передавать вещи по стоимости. Рассмотрим:
struct my_uint128_t {
    unsigned long hi;
    unsigned long lo;
};
my_uint128_t increment128_3(my_uint128_t x)
{
    const unsigned long hiAdd=0x0000062DE49B5241;
    const unsigned long loAdd=0x85DC198BCDD714BA;
    x.lo += loAdd;
    x.hi += hiAdd + (x.lo < loAdd);
    return x;
}
Сборка:
        .cfi_startproc
        movabsq     $-8801131483544218438, %rdx
        movabsq     $-8801131483544218439, %rax
        movabsq     $6794178679362, %rcx
        addq        %rsi, %rdx
        cmpq        %rdx, %rax
        sbbq        %rax, %rax
        addq        %rcx, %rax
        addq        %rdi, %rax
        ret
На самом деле это самый сложный код из трех.
... ОК, поэтому никто из них фактически не использовал перенос автоматически:-). Но они избегают условной ветки, и я уверен, что это медленная часть (поскольку логика предсказания ветвления будет ошибочной в два раза).
[edit 2]
И еще один, который я наткнулся на небольшое занятие. Знаете ли вы, что GCC имеет встроенную поддержку 128-битных целых чисел?
typedef unsigned long my_uint128_t __attribute__ ((mode(TI)));
my_uint128_t increment128_4(my_uint128_t x)
{
    const my_uint128_t hiAdd=0x0000062DE49B5241;
    const unsigned long loAdd=0x85DC198BCDD714BA;
    return x + (hiAdd << 64) + loAdd;
}
Сборка для этого примерно такая же хорошая, как и она:
        .cfi_startproc
        movabsq     $-8801131483544218438, %rax
        movabsq     $6794178679361, %rdx
        pushq       %rbx
        .cfi_def_cfa_offset 16
        addq        %rdi, %rax
        adcq        %rsi, %rdx
        popq        %rbx
        .cfi_offset 3, -16
        .cfi_def_cfa_offset 8
        ret
(Не знаю, откуда появился push/pop из ebx, но это все еще неплохо.)
Все это с GCC 4.5.2, кстати.
