This provides adi, sbi, mli, dvi, rmi, ngi, dvu, rmu 8, but is missing
shifts and rotates. It is also missing conversions between 8-byte
integers and other sizes of integers or floats. The code might not be
all correct, but works at least some of the time.
I adapted this from how ncg i86 does 4-byte integers, but I use a
different algorithm when dividing by a large value: i86 avoids the div
instruction and uses a shift-and-subtract loop; but I use the div
instruction to estimate a quotient, which is more like how big integer
libraries do division. My .dvi8 and .dvu8 also set ecx:ebx to the
remainder; this might be a bad idea, because it requires .dvi8 and
.dvu8 to always calculate the remainder, even when the caller only
wants the quotient.
To play with 8-byte integers, I wrote EM procedures like
mes 2, 4, 4
exp $ngi
pro $ngi,0
ldl 4
ngi 8
lol 0
sti 8
lol 0
ret 4
end
exp $adi
pro $adi,0
ldl 4
ldl 12
adi 8
lol 0
sti 8
lol 0
ret 4
end
and called them from C like
typedef struct { int l; int h; } q;
q ngi(q);
q adi(q, q);
20 lines
408 B
ArmAsm
20 lines
408 B
ArmAsm
.sect .text; .sect .rom; .sect .data; .sect .bss
|
|
.sect .text
|
|
.define .mli8
|
|
|
|
yl=4
|
|
yh=8
|
|
! xl in eax
|
|
! xh in edx
|
|
|
|
.mli8:
|
|
! x * y = (xh + xl) * (yh + yl)
|
|
! = xh * yh + xh * yl + xl * yh + xl * yl
|
|
! The term xh * yh overflows to zero.
|
|
mov ecx,eax
|
|
imul ecx,yh(esp) ! ecx = xl * yh
|
|
imul edx,yl(esp) ! edx = xh * yl
|
|
add ecx,edx
|
|
mul yl(esp) ! edx:eax = xl * yl
|
|
add edx,ecx ! edx:eax = x * y
|
|
ret 8
|