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

Calling CVF from IVF

Lewallen__Roy
Novice
600 Views

My problem is that I've been unable to call a function in a CVF (v. 6.6) compiled program with IVF (2020 Update 4), running on Windows 10, without an error.

I've spent several long days searching, reading, and trying everything I could think of, but I can't solve this programming problem. I need help!

Although I've been using Fortran for a long time, I've gotten along without really understanding most of what's going on under the hood. So please excuse my ignorance -- and the klutzy but hopefully functional programming.

The CVF function returns some numerical values in variables. When I run the calling IVF program in debug mode, I can see that all the returned values are correct. However, when exiting the IVF subroutine I get the error message

Run-Time Check Failure #2 - Stack around the variable '##' was corrupted.

where '##' is '.T3' when calling Example1 below that returns an array and '_EXP1$DCPXOUT5' when calling Example2 that returns individual values.

All the reading points to a problem with the different calling conventions of CVF and IVF. From their documentation it appears that that CVF adds the number of arguments but IVF doesn't, and IVF cleans up the stack and allows a variable number of arguments which CVF doesn't. If that's the problem, what I need to know is what ATTRIBUTES I need to put into the CVF procedures, or if I can just use !DEC$ ATTRIBUTES DLLEXPORT :: <subroutine name> in CVF and somehow fix the problem in the calling IVF subroutine. You can see I've added ALIAS attributes but that makes no difference, and other attributes I've tried don't solve the problem either. It's not clear what the INTERFACE blocks are supposed to do, and they make no difference one way or the other with regard to the problem. Or if I need to do something else, what?

To answer a question I'm sure I'll be asked -- why use CVF at all if I can modify the source files and compile it -- it's because CVF came with the IMSL math package. IVF (at least the "composer" version I have -- doesn't, and I want to use some of the IMSL functions. (IMSL now costs a lot of $$, especially for the hobby use I'm putting it to.) The plan is to make a CVF DLL that calls some functions and outputs them so they'll be available to IVF programs. The CVF compiler I had before migrating to Intel many years ago still runs on the old XP machine where it was originally installed -- it won't even try to install on my Windows 10-64 bit machine.

So can anyone please tell me what I need to do to get this to work? I'll appreciate it very much!

Of course I'm using the CVF DLL .lib file as a reference when building the IVF program, and both the CVF DLL and IVF program build without any errors or warnings.

Here are simplified versions of a couple of the CVF functions:

SUBROUTINE Example1(dcpx1, intDim, intOut, dcpxArray)

IMPLICIT NONE

!DEC$ ATTRIBUTES DLLEXPORT :: Example1
!DEC$ ATTRIBUTES ALIAS : "Example1" :: Example1

COMPLEX (KIND = :: dcpx1
INTEGER (KIND = 4) :: intDim
INTEGER (KIND = 4) :: intOut
COMPLEX (KIND = :: dcpxArray(1:intDim)
INTEGER (KIND = 4) :: intI
REAL (KIND = :: dre2

intOut = 5
dcpxArray(1) = dcpx1
DO intI = 2, intDim
dcpxArray(intI) = cmplx(intI, -1.1D0 * intI,
END DO
END SUBROUTINE Example1


SUBROUTINE Example2(dcpx1, intDim, intOut, dcpxOut1, &
dcpxOut2, dcpxOut3, dcpxOut4, dcpxOut5)

IMPLICIT NONE

!DEC$ ATTRIBUTES DLLEXPORT :: Example2
!DEC$ ATTRIBUTES ALIAS : "Example2" :: Example2

COMPLEX (KIND = :: dcpx1
INTEGER (KIND = 4) :: intDim
INTEGER (KIND = 4) :: intOut
COMPLEX (KIND = :: dcpxOut1
COMPLEX (KIND = :: dcpxOut2
COMPLEX (KIND = :: dcpxOut3
COMPLEX (KIND = :: dcpxOut4
COMPLEX (KIND = :: dcpxOut5
INTEGER (KIND = 4) :: intI
COMPLEX (KIND = :: dcpxArray(1:intDim)
INTEGER (KIND = 4) :: intMaxMinDim

COMPLEX (KIND = 8), PARAMETER :: dcpxZERO = (0.D0, 0.D0)

intOut = 5
intMaxMinDim = MAX(MIN(intDim, 5), 1)

dcpxOut1 = dcpx1
dcpxOut2 = cmplx(2., -2.2,
dcpxOut3 = cmplx(3., -3.3,
dcpxOut4 = dcpxZERO
dcpxOut5 = dcpxZERO
END SUBROUTINE Example2

-------- and the IVF calling program (which intentionally produce any output) ----------

INTEGER (KIND = 4) function WinMain(hInstance, hPrevInstance, &
lpszCmdLine, nCmdShow )

IMPLICIT NONE

!DEC$ ATTRIBUTES STDCALL, DECORATE, ALIAS : 'WinMain' :: WinMain

INTEGER (KIND = 4) :: hInstance
INTEGER (KIND = 4) :: hPrevInstance
INTEGER (KIND = 4) :: lpszCmdLine
INTEGER (KIND = 4) :: nCmdShow

WinMain = 0

Call Exp1
END FUNCTION WinMain

SUBROUTINE Exp1()

IMPLICIT NONE

INTERFACE
SUBROUTINE Example1(dcpx1, intDim, intOut, dcpxArray)
IMPLICIT NONE
!DEC$ ATTRIBUTES DLLEXPORT :: Example1
!DEC$ ATTRIBUTES ALIAS : "Example1" :: Example1
COMPLEX (KIND = :: dcpx1
INTEGER (KIND = 4) :: intDim
INTEGER (KIND = 4) :: intOut
COMPLEX (KIND = :: dcpxArray(1:intDim)
END SUBROUTINE Example1
END INTERFACE

INTERFACE
SUBROUTINE Example2(dcpx1, intDim, intOut, dcpxOut1, &
dcpxOut2, dcpxOut3, dcpxOut4, dcpxOut5)
IMPLICIT NONE
!DEC$ ATTRIBUTES DLLEXPORT :: Example2
!DEC$ ATTRIBUTES ALIAS : "Example2" :: Example2
COMPLEX (KIND = :: dcpx1
INTEGER (KIND = 4) :: intDim
INTEGER (KIND = 4) :: intOut
COMPLEX (KIND = :: dcpxOut1
COMPLEX (KIND = :: dcpxOut2
COMPLEX (KIND = :: dcpxOut3
COMPLEX (KIND = :: dcpxOut4
COMPLEX (KIND = :: dcpxOut5
END SUBROUTINE Example2
END INTERFACE

!DEC$ ATTRIBUTES DLLIMPORT :: Example1
!DEC$ ATTRIBUTES DLLIMPORT :: Example2

INTEGER (KIND = 4), PARAMETER :: intDIM = 3

COMPLEX (KIND = :: dcpx1
INTEGER (KIND = 4) :: intOut
COMPLEX (KIND = :: dcpxArray(1:intDim)
COMPLEX (KIND = :: dcpxOut1
COMPLEX (KIND = :: dcpxOut2
COMPLEX (KIND = :: dcpxOut3
COMPLEX (KIND = :: dcpxOut4
COMPLEX (KIND = :: dcpxOut5
INTEGER (KIND = 4) :: intI
INTEGER (KIND = 4) :: intMaxMinDim

dcpx1 = (2.D0, 3.D0)

CALL Example1(dcpx1, intDIM, intOut, dcpxArray)
CALL Example2(dcpx1, intDIM, intOut, dcpxOut1, &
dcpxOut2, dcpxOut3, dcpxOut4, dcpxOut5)

END SUBROUTINE Exp1

Thanks!

Roy

0 Kudos
7 Replies
Arjen_Markus
Honored Contributor I
587 Views

The CVF compiler used a different calling convention by default: STDCALL. This interferes with the current default, CDECL. The difference has to do with the way the stack is managed and a mismatch can therefore lead to all manner of interesting behaviour, most of which is completely unwanted.

In the properties window (External Procedures/Calling Convention) I see a number of options, one of them being /ifacecvf. My guess is that you will need this setting.

0 Kudos
mecej4
Black Belt
566 Views

Roy,

If you check any of the lines in your in-line Fortran code above that start with COMPLEX, you will see that some character sequences have been converted by the forum posting software to invisible smileys, so much of the code is "flyover territory". The next time when you wish to post, use the "code" button (first "..." button to expand the menu icons, then the </> icon,  choose Fortran and paste in the code). Or, zip up the source files and attach the zip to your post, or upload the zip file to a cloud server such as Google Drive and post a link in your post.

Now, to answer your question and make suggestions for moving forward. Which IMSL routines do you use? If you list them, it may be possible to suggest replacement routines from MKL, MATH77, or other libraries.

If you must use the IMSL 4.0 that came with CVF from Ifort compiled code, your choices are limited and error-prone. It so happens that it is possible to have CVF 6.6C installed and functioning on Windows-10/11, but the procedure is messy and to be avoided unless you are comfortable with assembler level code. Because CVF was copyrighted code, it is not possible to share files legally.

The least troublesome approach for using the IMSL 4.0 that came with CVF from Ifort-32-bit, in my view, is to build a 32-bit DLL from the IMSL 4.0 library that came with CVF, and to link to the associated import/export library from 32-bit Intel Ifort, along with the option /iface:cvf . For example, to build an EXE from Ifort 2021.8.0, using the example source code on p.591 of the IMSL MATH.PDF manual:

 

S:\IMSL>ifort /iface:cvf xqdags.f c:\LANG\cvf\DF98\IMSL\LIB\imsldll.lib

 

Again, let us note that the issue is about how to use 20 year-old "legacy" software with a current compiler, so failure should not be unexpected.

0 Kudos
JohnNichols
Valued Contributor III
548 Views

@mecej4 so failure should not be unexpected.

I had to laugh, my 15 year old daughter, who is sick and home from school, asked me a question at the weekend.  When I answered she stopped me and said, be direct Dad.  I read this sentence and thought kindly of a child who is miserable and thought "Expect failure".  

 

0 Kudos
BellamyDustin
Beginner
380 Views

@mecej4 wrote:

Roy,

If you check any of the lines in your in-line Fortran code above that start with COMPLEX, you will see that some character sequences have been converted by the forum posting software to invisible smileys, so much of the code is "flyover territory". The next time when you wish to post, use the "code" button (first "..." button to expand the menu icons, then the </> icon,  choose Fortran and paste in the code). Or, zip up the source files and attach the zip to your post, or upload the zip file to a cloud server such as Google Drive and post a link in your post.

Now, to answer your question and make suggestions for moving forward. Which IMSL routines do you use? If you list them, it may be possible to suggest replacement routines from MKL, MATH77, or other libraries.

If you must use the IMSL 4.0 that came with CVF from Ifort compiled code, your choices are limited and error-prone. It so happens that it is possible to have CVF 6.6C installed and functioning on Windows-10/11, but the procedure is messy and to be avoided unless you are comfortable with assembler level code. Because CVF was copyrighted code, it is not possible to share files legally.

The least troublesome approach for using the IMSL 4.0 that came with CVF from Ifort-32-bit, in my view, is to build a 32-bit DLL from the IMSL 4.0 library that came with CVF, and to link to the associated import/export library from 32-bit Intel Ifort, along with the option /iface:cvf . For example, to build an EXE from Ifort 2021.8.0, using the example source code on p.591 of the IMSL MATH.PDF manual:

 

S:\IMSL>ifort /iface:cvf xqdags.f c:\LANG\cvf\DF98\IMSL\LIB\imsldll.lib

 

Again, let us note that the issue is about how to use 20 year-old "legacy" software with a current compiler, so failure should not be unexpected.


I am looking for the same, your explanation is very well, great way to define each step, helpful for everyone especially for me, thanks 

0 Kudos
mecej4
Black Belt
544 Views

To @JohnNichols: Expect failure, then -- unless you are willing and can afford to put Hercules on the job.

0 Kudos
Lewallen__Roy
Novice
501 Views

Thanks for all the help! Setting the External Procedures to CVF (/iface:cvf) in the IVF calling program solved the problem of getting the results from the CVF compiled DLL. But although the example that I posted and was used for testing was an IVF .exe program, the intended object was an IVF DLL that I could call from other IVF programs or DLLs. And setting the External Procedures to CVF also affected the convention used for exporting routines. And again my ignorance of what's going on under the hood forced me into a trial and error mode to make the functions in that DLL exportable to other IVF objects.

 

The solution was simple, though. In the /iface:cvf DLL I simply added DEFAULT to all the procedure export statements :

     !DEC$ ATTRIBUTES DLLEXPORT, DEFAULT :: <procedure name>

So now I've got my IMSL functions usable and easily callable from a standard IVF program or DLL. The functions that I have immediate use for are Bessel and Kelvin functions with complex arguments, but I've come across standard and hyperbolic trig functions with complex arguments from time to time.

It's not uncommon for me to expect defeat, but I don't often accept it. And this was one of those cases where I was more determined to figure out how to get those IMSL functions than just to have them by some easier means.

Roy

JohnNichols
Valued Contributor III
377 Views

Well done, it is fun to get it right and then to tell the world, or a small subset.  

@mecej4 usually you are better at solving tough problems than Hercules.  

 

By the way, I often wondered why HGC had such graphics market share early on and then died.  

0 Kudos
Reply