El código Delphi antiguo a veces incluía un pequeño ayudante _ftol para convertir un valor de punto flotante a entero. En proyectos de 32 bits era común escribir este tipo de ayudante con ensamblador inline, especialmente en código gráfico y PDF optimizado para compiladores antiguos.
|
1 2 3 4 5 6 7 8 |
function _ftol( f: double) : Integer; cdecl; begin asm lea eax, f fstp qword ptr [eax] end; result := Trunc(f); end; |
Ese enfoque se rompe cuando la misma unidad se compila para un destino de 64 bits. El compilador Delphi de 64 bits informa E1025 Unsupported language feature: 'ASM' porque DCC64 no admite mezclar Pascal y ensamblador inline dentro de rutinas Pascal normales.
Por qué lo rechaza el compilador de 64 bits
DCC64 puede ensamblar rutinas de ensamblador de 64 bits, pero la rutina debe escribirse como una rutina ensambladora completa teniendo en cuenta la convención de llamada de 64 bits. No puedes copiar ensamblador inline de 32 bits dentro de una función Pascal y esperar que el compilador traduzca registros, diseño de pila o comportamiento x87.
Una versión completa en ensamblador es posible, y código como el siguiente muestra el tipo de manejo de palabra de control que puede requerirse cuando el valor ya está en la pila FPU.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function _ftol: Integer; cdecl; // Assumes double value is in FPU stack on entry // Make a truncation to integer and put it into function result var TmpVal: Int64; SaveCW, ScratchCW: word; asm .NOFRAME fnstcw word ptr [SaveCW] fnstcw word ptr [ScratchCW] or word ptr [ScratchCW], 0F00h ;// trunc toward zero, full precision fldcw word ptr [ScratchCW] fistp qword ptr [TmpVal] fldcw word ptr [SaveCW] mov rax, TmpVal end; |
Prefiere Pascal cuando el objetivo es solo truncar
Para la mayoría del código de aplicación, la rutina en ensamblador es innecesaria. Si el requisito real es truncar un Double hacia cero y devolver un entero, la versión clara y portable es simplemente:
|
1 2 3 4 |
function _ftol(f: double): integer; cdecl; begin Result := Trunc(f); end; |
Trunc expresa directamente la intención, compila para destinos de 32 y 64 bits y evita el coste de mantenimiento de ensamblador específico de arquitectura. También facilita que futuros mantenedores razonen sobre comprobaciones de rango y comportamiento de overflow.
Guía de migración
- Usa la implementación Pascal cuando controles el punto de llamada y solo necesites conversión numérica.
- Conserva una exportación ensambladora solo cuando la compatibilidad binaria exija un símbolo y convención de llamada concretos.
- No copies código de registros de 32 bits en una rutina de 64 bits sin revisar la convención de llamada y el ancho de datos.
- Prueba casos límite como valores negativos, valores grandes y valores fuera del rango del entero de destino.
Consideraciones de rango y comportamiento
Sustituir ensamblador por Trunc debe tratarse aun así como un cambio de comportamiento que merece pruebas. Confirma cómo debe comportarse tu código con números negativos, fracciones cerca de un límite entero y valores fuera del rango de Integer. El ensamblador antiguo puede haber dependido del estado de la palabra de control FPU, mientras que la versión Pascal sigue la implementación RTL del compilador de destino.
Si el ayudante está dentro de un componente PDF o gráfico, prueba salidas que usen texto rotado, coordenadas escaladas y comandos de dibujo transformados. Esas áreas tienen más probabilidades de revelar diferencias sutiles de conversión de flotante a entero que los ejemplos simples.
Ruta de migración recomendada
Primero, sustituye ayudantes privados de conversión por código Pascal claro cuando sea posible. Segundo, conserva la implementación original de 32 bits solo detrás de una condición de 32 bits si aún es necesaria. Tercero, añade una rama de 64 bits separada solo cuando un requisito medido de rendimiento o compatibilidad binaria lo justifique. Así la ruta portable sigue siendo simple y la ruta específica de arquitectura queda como excepción, no como predeterminada.