Ich habe die jeweils in reinem Pascal und x64 Assembler Code (weil der kürzer ist). Der Code funktioniert auch reibungslos solange ich mit ABI Calling Convention unterwegs bin. Da ich unter OSX entwickel bzw. Linux deployment stattfindet ist auch soweit alles ok.
Allerdings ist bei meinem Code derzeit Windows mit Assembler aussen vor, da dort eine andere Calling-Convention zum Einsatz kommt. u.a. kann ich einen Return Value vom Typ UInt128 nicht mit zwei 64-Bit Registern abbilden %rax:%rdx.
Frage: Fühlt sich jemand in der Lage die vier Assembler Methoden auch für Win64 Platform bereitzustellen ? Dann müsste ich auf der Platform nicht auf pascal Code zurückfallen.
Oder weiss jemand ob eine Int128 Unterstützung auf der Roadmap vom FPC irgendwo steht? Der Ursprungscode der mir vorliegt wurde mit gcc compiliert und dort ist eine native Int128 Unterstützung im Compiler vorhanden was den Assembler Code natürlich eleminieren würde

Es würde mich auch freuen wenn jemand die folgenden vier Methoden ebenfalls gebrauchen könnte, über jedweges Feedback freue ich mich.
Gruß Stefc
Code: Alles auswählen
{$IFDEF LITTLE_ENDIAN}
UInt128 = packed record
Lo,Hi: UInt64;
end;
{$ENDIF}
{$IFDEF BIG_ENDIAN}
UInt128 = packed record
Hi,Lo: UInt64;
end;
{$ENDIF}
{$IFDEF CPUX86_64}
function mul64x64_128(a,b: UInt64): UInt128; nostackframe; register; assembler;
asm
mov rax, b
mov rdx, a
mul rdx
end;
// %rdi,%rsi, %rdx => rax:rdx
function add128_64(a: UInt128; b: UInt64): UInt128; nostackframe; register; assembler;
asm
add rdi, b
jnc @1
inc rsi
@1:
mov rdx, rsi
mov rax, rdi
end;
function add128(a,b: UInt128): UInt128; nostackframe; register; assembler;
asm
add rdi, rdx
jnc @1
inc rsi
@1:
add rsi, rcx
mov rdx, rsi
mov rax, rdi
end;
function create128(hi,lo: UInt64): UInt128; nostackframe; register; assembler;
asm
mov rdx, hi
mov rax, lo
end;
{$ELSE}
function mul64x64_128(a,b: UInt64): UInt128;
const
HWORD_BITS = 32;
HWORD_MASK = $FFFFFFFF;
var
a_hi,a_lo,b_hi,b_lo: UInt32;
x0,x1,x2,x3: UInt64;
begin
a_hi := a shr HWORD_BITS;
a_lo := a and HWORD_MASK;
b_hi := b shr HWORD_BITS;
b_lo := b and HWORD_MASK;
x0 := UInt64(a_hi) * b_hi;
x1 := UInt64(a_lo) * b_hi;
x2 := UInt64(a_hi) * b_lo;
x3 := UInt64(a_lo) * b_lo;
// this cannot overflow as (2^32-1)^2 + 2^32-1 < 2^64-1
x2 := x2 + (x3 shr HWORD_BITS);
// this one can overflow
x2 := x2 + x1;
// propagate the carry if any
x0 := x0 + UInt64(x2 < x1) shl HWORD_BITS;
Result.Hi := x0 + (x2 shr HWORD_BITS);
Result.Lo := ((x2 and HWORD_MASK) shl HWORD_BITS) + (x3 and HWORD_MASK);
end;
function add128_64(a: UInt128; b: UInt64): UInt128;
var
p: UInt64;
begin
p := a.Lo;
Result.Lo := a.Lo + b;
Result.Hi := a.Hi + Ord(Result.Lo < p);
end;
function add128(a,b: UInt128): UInt128;
var
p: UInt64;
begin
p := a.Lo;
Result.Lo := a.Lo + b.Lo;
Result.Hi := a.Hi + b.Hi + Ord(Result.Lo < p);
end;
function create128(hi,lo: UInt64): UInt128;
begin
Result.Lo := lo;
Result.Hi := hi;
end;
{$ENDIF}