Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29236 Discussions

fortan and masm(ml) floating point examples

MWind2
New Contributor III
1,224 Views

Would anyone be able to provide a simple example of a fortran program that calls a masm procedure that does something with floating point, for example, add two doubles and return the result by reference?

0 Kudos
7 Replies
JVanB
Valued Contributor II
1,224 Views

Well, no. You didn't specify whether you wanted a 32-bit version or a 64-bit version. The calling conventions are different for the two ISAs. Functions would return their result by value, a 32-bit function in ST(0) and a 64-bit version in xmm0. If you want the result returned by reference I suppose you might mean a third, INTENT(OUT) argument to a subroutine.

You can generate your own example by writing a simple Fortran procedure that does no I/O and has the interface you want. Declare it PURE or RECURSIVE and BIND(C) and tell ifort to generate assembly language output. Post the .ASM file produced along with the original .F90 file if you want the forum to analyze it for you.

0 Kudos
SergeyKostrov
Valued Contributor II
1,224 Views

>>...Would anyone be able to provide a simple example of a fortran program that calls a masm
>>procedure that does something with floating point...

I could provide an implementation of a function in assembler that adds two Single-Precision
values and returns the result. Unfortunately, this is from a C/C++ set of tests I have.

Assembler Codes:

...
; C/C++ Declaration:
; float AddTwoSPValues( float fValue1, float fValue2 );

AddTwoSPValues PROC NEAR

PUSH ebp
MOV ebp, esp

FLD DWORD PTR [ebp+8]; Loads fValue1 into ST(0)
FADD DWORD PTR [ebp+12]; Adds fValue2 to ST(0)

MOV esp, ebp
POP ebp
; Visual Studio will correct ESP register and load a result
RET ; into an output variable from ST(0)

AddTwoSPValues ENDP
...

Test-Case in C/C++:

...
float fResult4 = 0.0f;
float fResultPI = 0.0f;

float fValue1 = 1.0f;
float fValue2 = 3.0f;

fResult4 = AddTwoSPValues( fValue1, fValue2 );
fResultPI = AddTwoSPValues( 3.0f, 0.1415926f );

printf( "[ Result4: %f ] [ ResultPI: %f ]\n", fResult4, fResultPI );
...

Output:

[ Result4: 4.000000 ] [ ResultPI: 3.141593 ]

Note:
As soon as a call is done a C/C++ compiler ( Visual Studio 2005 ) corrects ESP register and
loads a result into an output variable from ST(0)as follows:

...
call _AddTwoSPValues
add esp, 8
fstp dword ptr [fResult4]
...
call _AddTwoSPValues
add esp, 8
fstp dword ptr [fResultPI]
...

You will need to figure out how toproperly return a valuein case of a Fortran program.

0 Kudos
anthonyrichards
New Contributor III
1,224 Views
"You will need to figure out how toproperly return a valuein case of a Fortran program.". and there is the rub, if I recall correctly!
Notice the RET statement.
Depending on the calling convention, the RET may or may not have an argument, for example you may have to specify something like RET 4 or some such to clean up the stack.
0 Kudos
MWind2
New Contributor III
1,224 Views
I have got some things working with

[fortran]program alo1f USE, INTRINSIC :: ISO_C_BINDING implicit none interface subroutine addrefd( da, db, dc) bind(c) !DEC$ ATTRIBUTES C, ALIAS:'_addrefd' ::addrefd real(8),intent(in):: da real(8), intent(in):: db real(8), intent (inout) :: dc !DEC$ ATTRIBUTES REFERENCE :: da !DEC$ ATTRIBUTES REFERENCE :: db !DEC$ ATTRIBUTES REFERENCE :: dc end subroutine addrefd end interface real*8 :: d1 = 76.5 real*8 :: d2 = 43.1 real*8 :: d3 = 128.0 call addrefd(d1,d2, d3) end program alo1f [/fortran]and
[plain]addrefd proc C push ebp mov ebp, esp mov eax, DWORD PTR [ebp+8] mov edx, DWORD PTR [ebp+12] fld QWORD PTR [eax] fld QWORD PTR [edx] faddp st(1), st mov eax, DWORD PTR [ebp+16] fstp QWORD PTR [eax] pop ebp ;leave ret addrefd endp[/plain]
0 Kudos
mecej4
Honored Contributor III
1,224 Views
A short procedure such as addrefd does not need its own stack, and since the 80386 we can use the stack pointer in reg/mem expressions. The following shorter version uses this property.
[bash]addrefd proc C mov eax, DWORD PTR [esp+4] mov edx, DWORD PTR [esp+8] fld QWORD PTR [eax] fadd QWORD PTR [edx] mov eax, DWORD PTR [esp+12] fstp QWORD PTR [eax] ret addrefd endp [/bash]


0 Kudos
SergeyKostrov
Valued Contributor II
1,224 Views
...Depending on the calling convention, the RET may or may not have an argument, for example you may

[SergeyK] Yes, that's right.

have to specify something like RET 4 or some such to clean up the stack...


In my case everything is correct because aC/C++ compileruses a forwarddeclarationfor the function:
...
float AddTwoSPValues( float fValue1, float fValue2 );
...
and addsa cleanupinstruction after the call:
...
call _AddTwoSpValues
add esp, 8
...

0 Kudos
Steven_L_Intel1
Employee
1,224 Views
You simply have to follow the "C" calling convention and it will be fine. A simple RET will do. RET 4 and the like is when you have chosen to write a STDCALL routine, and you'd then need to tell Fortran it was STDCALL.
0 Kudos
Reply