Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 装配ADC(带进位)到C++;_C++_Assembly_X86_Bigint_Carryflag - Fatal编程技术网

C++ 装配ADC(带进位)到C++;

C++ 装配ADC(带进位)到C++;,c++,assembly,x86,bigint,carryflag,C++,Assembly,X86,Bigint,Carryflag,有一条x86汇编指令ADC。我发现这意味着“加上携带”。这意味着什么?如何在C++中实现这个指令的行为? 信息: 在Windows上编译。我使用的是32位Windows安装。我的处理器是Intel的Core 2 Duo。ADC与ADD相同,但如果设置了处理器的进位标志,则会额外添加1。来自(断开)或 然而,英特尔处理器 有一个叫做adc的特殊指令。 此命令的行为与 添加命令。唯一额外的是 它还添加了值进位标志 一路走。所以,这可能是非常方便的 添加大整数。如果你愿意的话 将32位整数与16位整数

有一条x86汇编指令
ADC
。我发现这意味着“加上携带”。这意味着什么?如何在C++中实现这个指令的行为?

信息:

在Windows上编译。我使用的是32位Windows安装。我的处理器是Intel的Core 2 Duo。

ADC与ADD相同,但如果设置了处理器的进位标志,则会额外添加1。

来自(断开)或

然而,英特尔处理器 有一个叫做adc的特殊指令。 此命令的行为与 添加命令。唯一额外的是 它还添加了值进位标志 一路走。所以,这可能是非常方便的 添加大整数。如果你愿意的话 将32位整数与16位整数相加 登记册。我们怎么能做到呢?好, 假设第一个整数是 保持在寄存器对DX:AX上,和 第二个是关于BX:CX的。这是 如何:

啊,首先,下面的16位加上 添加ax、cx。那么较高的16位是 使用adc而不是add添加。它是 因为:如果有溢出,则 进位自动添加到 更高的16位。所以,没有麻烦 检查。这种方法可以推广 到64位等等。。。注意:如果 32位整数加法溢出 同样在较高的16位,结果 将不正确,并且进位标志 已设置,例如,将50亿添加到5 亿

从现在开始,请记住,它几乎属于实现定义行为的范围

下面是一个适用于VS2010的小示例(32位,WinXp)

警告:$7.4/1-“asm声明是有条件支持的;其含义是实现定义的。[注意:通常用于通过实现将信息传递给汇编程序。-结束说明]”


< C > C++中的ADC行为可以模拟。下面的示例添加两个数字(存储为无符号数组,因为它们太大,无法装入单个无符号数组)

unsigned first[10];
无符号秒[10];
无符号结果[11];
....   /* 第一个和第二个得到定义*/
无符号进位=0;
对于(i=0;i<10;i++){
结果[i]=第一[i]+第二[i]+进位;
进位=(第一[i]>结果[i]);
}
结果[10]=进位;

希望这有帮助。

这里面有一个bug。尝试以下输入:

unsigned first[10] =  {0x00000001};
unsigned second[10] = {0xffffffff, 0xffffffff};
结果应该是{0,0,1,…},但结果是{0,0,0,…}

更改此行:

carry = (first[i] > result[i]);
为此:

if (carry)
    carry = (first[i] >= result[i]);
else
    carry = (first[i] > result[i]);

修复.< /P> < P> C++语言没有任何进位标志的概念,所以在一个笨拙的地方做一个内在的函数包装。不过,英特尔还是做到了:。上次我检查时,gcc在这方面做得很差(将进位结果保存到整数寄存器中,而不是保留在CF中),但希望Intel自己的编译器做得更好

有关部件文档,请参见标记wiki


在添加比单个寄存器宽的整数时,编译器将为您使用ADC,例如在32位代码中添加
int64\u t
,或在64位代码中添加
\uu int128\u t

#include <stdint.h>
#ifdef __x86_64__
__int128_t add128(__int128_t a, __int128_t b) { return a+b; }
#endif
    # clang 3.8 -O3  for x86-64, SystemV ABI.
    # __int128_t args passed in 2 regs each, and returned in rdx:rax
    add     rdi, rdx
    adc     rsi, rcx
    mov     rax, rdi
    mov     rdx, rsi
    ret
使用针对x86-64()的铿锵主干
-O2
编译如下:

add(int已灭绝,int已灭绝):
加上rsi,r9
adc-rdx,qword-ptr[rsp+8]
adc-rcx,qword-ptr[rsp+16]
mov rax,rdi#返回retval指针
adc r8,qword ptr[rsp+24]#ADD链/3x adc!
mov qword ptr[rdi+8],rdx#将结果存储到mem
mov qword ptr[rdi],rsi
mov qword ptr[rdi+16],rcx
mov qword ptr[rdi+24],r8
ret
显然,
\u exet
在整数寄存器中按值传递,直到调用约定用完寄存器为止。(至少在这个早期版本中;当x86-64 SysV的宽度超过2个或3个寄存器时,可能应该将其归类为“内存”,比如大于16字节的结构。尽管比结构更大,但在寄存器中使用它可能很有用。只需先放置其他参数,这样它们就不会被替换。)

第一个已灭绝的arg在R8:RCX:RDX:RSI中,第二个在R9中有它的低qword,其余的在内存中

返回值对象的指针作为RDI中隐藏的第一个参数传递;x86-64 System V最多只能返回2个整数寄存器(RDX:RAX),这不会改变这一点。

int32_t adc(uint32_t first,uint32_t second,uint32_t*carry)
{
uint32_t res;
uint32执行=0;
如果(!*进位)
{
res=第一+第二;
*进位=(进位<第一位)&(进位<第二位);
返回res;
}
res=adc(第一次、第二次和执行);
如果(*进位)
{
res++;
执行|=!res;
}
*执行;
返回res;
}

@Chubsdad:我已经尽力添加了一些信息。我希望足够了。哪个编译器?要访问进位标志,必须将汇编代码嵌入到C++代码中。你如何做到这一点取决于你使用的编译器。好的!非常感谢。但现在,我必须知道是否设置了标志。这是否可能在C++中?不是用标准C++,你必须使用一个“ASM”代码块。我不记得确切的语法,但是你会失去代码的可移植性。ADC的思想不是知道进位标志,而是在ADC之前进行ADD,所以进位将在ADC时设置overflows@Martijn,如果你想知道进位标志的状态,你可以这样做:pushfd;pop-eax;现在的进位标志是EAX的0位,因为没有真正回答C++的问题。另外,与
setc al
(和
movzx-eax,al
相比,asm序列有点差劲
pushf
是英特尔SnB系列CPU上的一条3-uop指令。push/pop store forwarding往返为涉及CF的依赖链增加了约5个延迟周期。我无法阻止引用'C'
carry = (first[i] > result[i]);
if (carry)
    carry = (first[i] >= result[i]);
else
    carry = (first[i] > result[i]);
#include <stdint.h>
#ifdef __x86_64__
__int128_t add128(__int128_t a, __int128_t b) { return a+b; }
#endif
    # clang 3.8 -O3  for x86-64, SystemV ABI.
    # __int128_t args passed in 2 regs each, and returned in rdx:rax
    add     rdi, rdx
    adc     rsi, rcx
    mov     rax, rdi
    mov     rdx, rsi
    ret
typedef _ExtInt(256) wide_int;

wide_int add ( wide_int a, wide_int b) {
    return a+b;
}
add(int _ExtInt<256>, int _ExtInt<256>):
        add     rsi, r9
        adc     rdx, qword ptr [rsp + 8]
        adc     rcx, qword ptr [rsp + 16]
        mov     rax, rdi                        # return the retval pointer
        adc     r8, qword ptr [rsp + 24]        # chain of ADD / 3x ADC!

        mov     qword ptr [rdi + 8], rdx        # store results to mem
        mov     qword ptr [rdi], rsi
        mov     qword ptr [rdi + 16], rcx
        mov     qword ptr [rdi + 24], r8
        ret