ÐÑигиналниÑÑ Ð¸Ð·Ñаз _ftol в 32-биÑова Delphi изглежда каÑо Ñмно едноÑедово ÑеÑение: обвивка на Pascal ÑÑнкÑиÑ, коÑÑо пÑеминава вÑв вгÑаден аÑемблеÑ, за да манипÑлиÑа конÑÑолнаÑа дÑма на x87 FPU, да оÑÑеже ÑÑойноÑÑÑа в FPU ÑÑека и да извлеÑе ÑезÑлÑаÑа. Той Ñе компилиÑаÑе ÑÑпеÑно под DCC32 дÑлго вÑеме, коеÑо е пÑиÑинаÑа да Ñе озове в Ñолкова много по-ÑÑаÑи гÑаÑиÑни и PDF модÑли, без никой да го подлага на ÑÑмнение.
ÐÑевклÑÑеÑе ÑелÑа на компилаÑÐ¸Ñ ÐºÑм 64-биÑова и компилаÑоÑÑÑ ÑпиÑа Ñ Ð³ÑеÑка E1025 Unsupported language feature: 'ASM'. Тази гÑеÑка не е пÑоÑÑо пÑедÑпÑеждение за ÑÑвмеÑÑимоÑÑ. Ð¢Ñ Ð¾Ð·Ð½Ð°Ñава, Ñе DCC64 изобÑо нÑма да компилиÑа ÑÑÑинаÑа, незавиÑимо колко добÑе е ÑабоÑил аÑемблеÑниÑÑ ÐºÐ¾Ð´ пÑеди Ñова.
ÐÑигиналниÑÑ 32-биÑов код обикновено изглеждаÑе по ÑÐ»ÐµÐ´Ð½Ð¸Ñ Ð½Ð°Ñин:
function _ftol(f: Double): Integer; cdecl;
begin
asm
lea eax, f
fstp qword ptr [eax]
end;
Result := Trunc(f);
end;
Този asm блок в ÑÑлоÑо begin...end на Pascal е ÑоÑно Ñова, коеÑо DCC64 оÑÑ
вÑÑлÑ. ÐваÑа компилаÑоÑа Ð¸Ð¼Ð°Ñ ÑазлиÑни пÑавила за Ñова кÑде е ÑазÑеÑен аÑемблеÑниÑÑ ÐºÐ¾Ð´, и Ñази гÑаниÑа е важна.
ÐаÑо DCC64 поÑÑÐ°Ð²Ñ Ð³ÑаниÑаÑа по ÑазлиÑен наÑин
DCC32 позволÑва вгÑаден аÑÐµÐ¼Ð±Ð»ÐµÑ Ð² обикновени Pascal ÑÑÑини. ÐомпилаÑоÑÑÑ Ð¿Ð¾Ð·Ð½Ð°Ð²Ð° 32-биÑоваÑа конвенÑÐ¸Ñ Ð·Ð° извикване и може да опÑедели кÑде Ñе намиÑÐ°Ñ Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸Ñе пÑоменливи и паÑамеÑÑиÑе, Ñака Ñе допÑÑка аÑемблеÑни ÑÑагменÑи, коиÑо Ð¸Ð¼Ð°Ñ Ð´Ð¾ÑÑÑп до ÑамкаÑа на ÑÑека по име. DCC64 заема по-ÑÑÑога позиÑиÑ: аÑемблеÑниÑÑ ÐºÐ¾Ð´ ÑÑÑбва да бÑде в оÑделна аÑемблеÑна ÑÑнкÑиÑ, кÑдеÑо ÑÑлоÑо ÑÑло е аÑемблеÑен код и конвенÑиÑÑа за извикване Ñе ÑпÑавлÑва изÑиÑно. СмеÑениÑÑ Pascal-плÑÑ-asm код изобÑо не Ñе поддÑÑжа.
ÐÑновнаÑа пÑиÑина е аÑÑ
иÑекÑÑÑна. Ð 64-биÑоваÑа конвенÑÐ¸Ñ Ð·Ð° извикване в Windows (Microsoft ABI), пÑÑвиÑе ÑеÑиÑи паÑамеÑÑÑа пÑиÑÑÐ¸Ð³Ð°Ñ Ð² RCX, RDX, R8 и R9 за ÑелоÑиÑлени Ñипове, или в XMM0 до XMM3 за плаваÑа запеÑаÑ. ÐÑма ÑÑаÑÑие на x87 FPU пÑи ноÑмалноÑо пÑедаване на паÑамеÑÑи; x87 е ÑеÑ
ниÑеÑки налиÑен, но ABI не го използва за ÑÑанÑпоÑÑ Ð½Ð° аÑгÑменÑи. ÐÑемблеÑниÑÑ ÐºÐ¾Ð´, койÑо пÑедполага, Ñе ÑÑойноÑÑÑа е "в ÑÑека на FPU", ÑазÑÑждава за ÑÑÑÑоÑние, коеÑо 64-биÑовиÑÑ ABI никога не ÑÑздава.
Така Ñе ÑÑаÑиÑÑ ÑÑÐ°Ð³Ð¼ÐµÐ½Ñ Ð½Ñма пÑоÑÑо ÑинÑакÑиÑен пÑоблем. ÐоÑи ако DCC64 го пÑиемаÑе, пÑедположениÑÑа за ÑегиÑÑÑиÑе ÑÑÑ Ð° да бÑÐ´Ð°Ñ Ð³ÑеÑни.
ÐапиÑване на пÑавилна 64-биÑова аÑемблеÑна веÑÑиÑ
ÐогаÑо наиÑÑина ÑÑÑбва да екÑпоÑÑиÑаÑе Ñимвол _ftol Ñ ÐºÐ¾Ð½Ð²ÐµÐ½ÑÐ¸Ñ cdecl за двоиÑна ÑÑвмеÑÑимоÑÑ, ÑÑнкÑиÑÑа ÑÑÑбва да бÑде напиÑана каÑо ÑиÑÑа аÑемблеÑна ÑÑÑина. Ðод 64-биÑÐ¾Ð²Ð¸Ñ ABI паÑамеÑÑÑÑÑ Ð¾Ñ Ñип Double пÑиÑÑига в XMM0, а ÑелоÑиÑлениÑÑ ÑезÑлÑÐ°Ñ ÑÑÑбва да бÑде в RAX пÑи вÑÑÑане. ÐиÑекÑиваÑа .NOFRAME Ñказва на DCC64, Ñе ÑÑÑинаÑа ÑпÑавлÑва ÑобÑÑÐ²ÐµÐ½Ð¸Ñ Ñи ÑÑек, коеÑо е подÑ
одÑÑо за Ñолкова кÑаÑка кÑайна (leaf) ÑÑнкÑиÑ:
function _ftol: Integer; cdecl;
// Double value expected in XMM0 per 64-bit ABI
asm
.NOFRAME
cvttsd2si rax, xmm0 // truncate-to-integer, result in rax
end;
CVTTSD2SI е SSE2 инÑÑÑÑкÑиÑÑа за конвеÑÑиÑане на ÑиÑло Ñ Ð¿Ð»Ð°Ð²Ð°Ñа запеÑÐ°Ñ Ñ Ð´Ð²Ð¾Ð¹Ð½Ð° ÑоÑноÑÑ Ð² ÑелоÑиÑлено ÑиÑло ÑÑÑ Ð·Ð½Ð°Ðº Ñ Ð¾ÑÑÑзване кÑм нÑлаÑа, коеÑо е ÑоÑно Ñова, коеÑо ÑÑÑбва да пÑави _ftol. Това е една инÑÑÑÑкÑиÑ, коÑÑо взема паÑамеÑÑÑа диÑекÑно Ð¾Ñ Ð¼ÑÑÑоÑо, кÑдеÑо ABI го е оÑÑавил, и поÑÑÐ°Ð²Ñ ÑезÑлÑаÑа Ñам, кÑдеÑо ABI го оÑаква. Ðе е необÑ
одимо никакво манипÑлиÑане на конÑÑолнаÑа дÑма на FPU.
ÐмайÑе пÑедвид, Ñе ако вÑ
однаÑа ÑÑойноÑÑ Ð½Ð°Ð´Ñ
вÑÑÐ»Ñ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° на 32-биÑово ÑелоÑиÑлено ÑиÑло ÑÑÑ Ð·Ð½Ð°Ðº, CVTTSD2SI вÑÑÑа неопÑеделенаÑа ÑелоÑиÑлена ÑÑойноÑÑ ($80000000). Това е ÑÑÑоÑо поведение каÑо на x87 fistp пÑи ÑÑойноÑÑи извÑн диапазона. ÐобÑе е да поÑвÑÑдиÑе дали ваÑиÑе Ð¸Ð·Ð²Ð¸ÐºÐ²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð³Ð°Ñ Ð´Ð° генеÑиÑÐ°Ñ Ñакива ÑÑойноÑÑи, пÑеди да ÑÑиÑаÑе мигÑаÑиÑÑа за завÑÑÑена.
Ðога Trunc е по-добÑоÑо ÑеÑение
ÐÑемблеÑнаÑа веÑÑÐ¸Ñ Ð¿Ð¾-гоÑе Ñи ÑÑÑÑва да Ñе пиÑе Ñамо когаÑо имаÑе дейÑÑвиÑелно изиÑкване за двоиÑна ÑÑвмеÑÑимоÑÑ: нÑкой вÑнÑен код оÑаква Ñимвола _ftol ÑÑÑ ÑпеÑиÑиÑна конвенÑÐ¸Ñ Ð·Ð° извикване и не можеÑе да пÑомениÑе Ñези извикваниÑ. Тази ÑиÑÑаÑÐ¸Ñ Ðµ ÑÑдка. ÐÑез повеÑеÑо вÑеме _ftol е била ÑаÑÑна помоÑна ÑÑнкÑиÑ, използвана Ñамо в ÑамкиÑе на ÑÑÑÐ¸Ð¸Ñ Ð¼Ð¾Ð´Ñл, и изобÑо нÑма вÑнÑна завиÑимоÑÑ Ð¾Ñ Ð½ÐµÐ¹Ð½Ð¾Ñо име или конвенÑиÑ.
Ðа Ñози ÑлÑÑай Ñ Ð·Ð°Ð¼ÐµÐ½ÐµÑе Ñ ÑиÑÑ Pascal:
function _ftol(f: Double): Integer; cdecl;
begin
Result := Trunc(f);
end;
Trunc оÑÑÑзва ÑÑойноÑÑÑа кÑм нÑлаÑа, коеÑо ÑÑвпада Ñ Ñова, коеÑо пÑавеÑе _ftol Ñ ÐºÐ¾Ð½ÑÑолнаÑа дÑма на x87, наÑÑÑоена в Ñежим на оÑÑÑзване. Ð¢Ñ Ñе компилиÑа на DCC32 и DCC64 без модиÑикаÑиÑ. ÐомпилаÑоÑÑÑ Ð³ÐµÐ½ÐµÑиÑа подÑ
одÑÑаÑа инÑÑÑÑкÑÐ¸Ñ Ð·Ð° вÑÑка Ñел: на x64 Ñой обикновено излÑÑва CVTTSD2SI Ñака или инаÑе, ÑÑÑаÑа инÑÑÑÑкÑÐ¸Ñ ÐºÐ°Ñо ÑÑÑно напиÑанаÑа веÑÑиÑ. ÐолÑÑаваÑе иденÑиÑно поведение, липÑа на ÑÑловна компилаÑÐ¸Ñ Ð·Ð° плаÑÑоÑми и никакÑв аÑемблеÑен код за поддÑÑжка.
ÐдинÑÑвенаÑа ÑеманÑиÑна Ñазлика, коÑÑо Ñи ÑÑÑÑва да Ñе пÑовеÑи: Trunc пÑедизвиква изклÑÑение EInvalidOp в конÑигÑÑаÑиÑÑа по подÑазбиÑане на Delphi, когаÑо вÑ
однаÑа ÑÑойноÑÑ Ðµ NaN или безкÑайноÑÑ. x87 fistp в оÑÐ¸Ð³Ð¸Ð½Ð°Ð»Ð½Ð¸Ñ ÐºÐ¾Ð´ пÑоÑÑо запиÑваÑе биÑов модел, без да пÑедизвиква ниÑо. Ðко ваÑиÑÑ ÐºÐ¾Ð´ подава необиÑайни ÑÑойноÑÑи Ñ Ð¿Ð»Ð°Ð²Ð°Ñа запеÑÐ°Ñ ÐºÑм Ñази ÑÑнкÑÐ¸Ñ Ð¸ ÑÑаÑоÑо поведение е било ÑиÑ
о, използвайÑе IsNaN и IsInfinite Ð¾Ñ Math, пÑеди да извикаÑе Trunc.
УÑловна компилаÑÐ¸Ñ Ð¿Ñи запазване на акÑивноÑÑÑа и на двеÑе Ñели
ÐÑкои пÑоекÑи ÑÑÑбва да пÑодÑÐ»Ð¶Ð°Ñ Ð´Ð° доÑÑавÑÑ ÐºÐ°ÐºÑо 32-биÑови, Ñака и 64-биÑови изпÑлними Ñайлове. Ðко оÑигиналнаÑа аÑемблеÑна веÑÑÐ¸Ñ ÑÑÑбва да бÑде запазена за 32-биÑоваÑа веÑÑÐ¸Ñ Ð¸ да бÑде пÑедоÑÑавено ново изпÑлнение за 64-биÑоваÑа, използвайÑе ÑÑÐ»Ð¾Ð²Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»Ð°ÑÐ¾Ñ CPUX64:
function _ftol(f: Double): Integer; cdecl;
begin
{$IFDEF CPUX64}
Result := Trunc(f);
{$ELSE}
// 32-bit path: DCC32 accepts inline asm
asm
lea eax, f
fstp qword ptr [eax]
end;
Result := Trunc(f);
{$ENDIF}
end;
Това е минималнаÑа Ð¼ÐµÑ Ð°Ð½Ð¸Ñна коÑекÑÐ¸Ñ Ð¸ Ñи ÑÑÑÑва да Ñе ÑÑеÑиÑа каÑо вÑеменна. Ðодова база, коÑÑо ноÑи ÑпеÑиÑиÑен за аÑÑ Ð¸ÑекÑÑÑаÑа аÑемблеÑен код в помоÑна ÑÑнкÑиÑ, ÑиÑÑо единÑÑвена Ñел е оÑÑÑзване Ð¾Ñ Ð¿Ð»Ð°Ð²Ð°Ñа запеÑÐ°Ñ Ð´Ð¾ ÑÑло ÑиÑло, ноÑи излиÑен ÑÐµÑ Ð½Ð¸ÑеÑки дÑлг. 32-биÑовиÑÑ ÐºÐ»Ð¾Ð½ може да изÑезне изÑÑло, Ñлед каÑо поÑвÑÑдиÑе, Ñе ниÑо не завиÑи Ð¾Ñ ÑÑÑаниÑниÑе еÑекÑи на FPU Ð¾Ñ ÑÑаÑоÑо изпÑлнение.
Ðко ÑÑнкÑиÑÑа Ñе поÑвÑва в компоненÑ, използван в множеÑÑво модÑли, поÑÑÑÑеÑе в ÑÑлаÑа кодова база за _ftol, пÑеди да ÑеÑиÑе как да мигÑиÑаÑе. Символ Ñ Ñова име може да бÑде деклаÑиÑан на повеÑе Ð¾Ñ ÐµÐ´Ð½Ð¾ мÑÑÑо; ÑвÑÑзваÑиÑÑ ÑедакÑÐ¾Ñ (linker) избиÑа ÐµÐ´Ð¸Ð½Ð¸Ñ Ð¸ мÑлÑаливо игноÑиÑа оÑÑаналиÑе, коеÑо ознаÑава, Ñе можеÑе да коÑигиÑаÑе едно копие, но вÑе пак да Ñе ÑвÑÑжеÑе Ñ Ð´ÑÑго, коеÑо не е било докоÑнаÑо.