I've implemented a 256 bit integer using an array of unsigned long long
and used x64 assembly to implement the add with carry. Here's the C++ caller:
#include "stdafx.h"
extern "C" void add256(unsigned long long *a, unsigned long long * b, unsigned long long *c);
int _tmain(int argc, _TCHAR* argv[])
{
unsigned long long a[4] = {0x8000000000000001, 2, 3, 4};
unsigned long long b[4] = {0x8000000000000005, 6, 7, 8};
unsigned long long c[4] = {0, 0, 0, 0};
add256(a, b, c); // c[] == {6, 9, 10, 12};
return 0;
}
The add256
is implemented in assembly:
; void add256(unsigned long long *a, unsigned long long * b, unsigned long long *c)
.CODE
PUBLIC add256
add256 PROC
mov qword ptr [rsp+18h],r8
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+8],rcx
push rdi
; c[0] = a[0] + b[0];
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax]
mov rcx,qword ptr 24[rsp]
add rax,qword ptr [rcx]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx],rax
; c[1] = a[1] + b[1] + CARRY;
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax+8]
mov rcx,qword ptr 24[rsp]
adc rax,qword ptr [rcx+8]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx+8],rax
; c[2] = a[2] + b[2] + CARRY;
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax+10h]
mov rcx,qword ptr 24[rsp]
adc rax,qword ptr [rcx+10h]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx+10h],rax
; c[3] = a[3] + b[3] + CARRY;
mov rax,qword ptr 16[rsp]
mov rax,qword ptr [rax+18h]
mov rcx,qword ptr 24[rsp]
adc rax,qword ptr [rcx+18h]
mov rcx,qword ptr 32[rsp]
mov qword ptr [rcx+18h],rax
; }
pop rdi
ret
add256 endp
end
I know you indicating you didn't want an emulated add with carry solution, and wanted a high performing solution, but, still, you may consider the following C++ only solution which has a nice way of simulating 256 bit numbers:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
unsigned long long a[4] = {0x8000000000000001, 2, 3, 4};
unsigned long long b[4] = {0x8000000000000005, 6, 7, 8};
unsigned long long c[4] = {0, 0, 0, 0};
c[0] = a[0] + b[0]; // 6
c[1] = a[1] + b[1] + (c[0] < a[0]); // 9
c[2] = a[2] + b[2] + (c[1] < a[1]); // 10
c[3] = a[3] + b[3] + (c[2] < a[2]); // 12
return 0;
}