Porting from Silverfrost FTN95 - anyone been here before?

Porting from Silverfrost FTN95 - anyone been here before?

Hi,

I'm evaluating IVF with a view to "changing horses" from Silverfrost's FTN95 compiler.  I've tried compiling a source file with module definitions but get "loads of errors" that I don't know how to fix.  Has anyone trod this path before and is prepared to get me kick-started by "fixing" the attached source file?

TIA

K

AnexoTamanho
Download d-type.for203.22 KB
115 posts / novo 0
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.

Give your filename a .f90 extension, and try again.  The Intel compiler assumes that .for and .f files are fixed form.

(Alternatively, explicitly tell the compiler that the file is free form by using the /free command line option, or pop the !DEC$ FREEFORM compiler directive in the source - I see a similar directive already in there for silverfrost.)

thanks Ian, i'd already spotted that and have the /fr switch in my compile script.  Here's an example of what i'm left with:

d_type.for(100): error #6516: This attribute specification is not valid for a component definition statement.   [TARGET]
  TYPE (AXSC), TARGET   :: SCA(10)
---------------^

d_type.for(153): error #6249: This symbol has multiple TARGET statement/attribute declarations which is not allowed.   [SCA]
  TYPE (AXSC), TARGET   :: SCA(10)
---------------------------^

d_type.for(959): error #6027: All derived type fields within a sequenced type must be of a derived-type that is sequenced (R424.2).   [ZPS]
  TYPE (ZPSET), POINTER :: ZPS=>Null(), CZPS
---------------------------^

K

If Silverfrost allowed TARGET in a TYPE declaration, that's either a bug or a pointless extension. TARGET is an attribute for variables. Just remove those TARGET attributes.

The third error is also valid - any components of a SEQUENCE type must themselves be SEQUENCE types. So add SEQUENCE to the declaration of type ZPSET.

I recommend renaming the file rather than use /fr.

Steve - Intel Developer Support

Your d-type.f90 file requires the source for a module, AUX_INT, which you forgot to provide. Given that your source file is rather long, I'll note that the lines that you showed (above, in-line) pertain to components of a derived type. Thus, you are attempting to specify TARGET as an attribute of individual components, which is what Steve wrote about.

Steve, that's great, i'm getting close now.  just got this left:

d_type.for(8412): error #7835: Record fields or array elements or sections of pointers are not themselves pointers.   [ASSOCIATED]
            IF( ASSOCIATED(W(L)%AX(J)) ) CALL DT_RVECDel (W(L)%AX(J))

Here's the source snippet (error line indicated by *******s):

TYPE WXP
  INTEGER        :: JW, IZ, ITRCH, USE
  TYPE (IVEC), POINTER    :: IX(:)
  TYPE (RVEC), POINTER    :: AX(:)
  END TYPE WXP
.

.

SUBROUTINE DT_WReset (W)

  TYPE (WXP)    :: W(:)

    N    =  SIZE(W)
    DO L = N, 1, -1
     IF( ASSOCIATED(W(L)%AX) ) THEN
       NA    =  SIZE(W(L)%AX)
       DO J = NA, 1, -1
*****        IF( ASSOCIATED(W(L)%AX(J)) ) CALL DT_RVECDel (W(L)%AX(J))
       END DO

what's the fix for this? I'm assuming I either have to change the definition of AX to be something other than a pointer or change "associated" to something else - what's best?

Thanks for your help!

K

Simply remove the superfluous and erroneous " IF( ASSOCIATED(W(L)%AX(J)) )". The source code seems to have been written with confusion between "pointer to array" and "array of pointers". 

Citação:

mecej4 escreveu:

Simply remove the superfluous and erroneous " IF( ASSOCIATED(W(L)%AX(J)) )". The source code seems to have been written with confusion between "pointer to array" and "array of pointers". 

I have to say that this isn't my code originally, but if I understand the intention, removing the test will try to delete the memory whether it has been allocated or not, which will surely result in a runtime error, won't it?

Tks

K

PS, ...but not if the SIZE function is doing its job I guess!

PPS, i tried to upload that missing file but i keep getting errors when i do...

Citação:

Kenny T escreveu:
 removing the test will try to delete the memory whether it has been allocated or not, which will surely result in a runtime error, won't it?

No, because the statements in the IF .. ENDIF construct will be skipped if W(L)%AX is not associated, and SIZE will not even be evaluated.

To attach a file, give it one of the approved endings and drag-drop into the Attachments area, or zip it and attach the zip file.

trying again...ok, it worked this time.  i didn't do anything different (honest!)

K

Anexos: 

AnexoTamanho
Download auxp-int.for7.47 KB

By adding the SEQUENCE attribute to a number of your user-defined types, and removing the  " IF( ASSOCIATED(W(L)%AX(J)) )" clauses as directed by the compiler, I was able to compile your two files with just warnings of misalignment and no errors.  That is neither here nor there if, as a result of adding the SEQUENCE attribute to them, your types are no longer compatible with the library that you are going to link your code with as to memory layout.

thanks, mecej4 and Steve.  much appreciated!

K

One item to be sure you realize: Intel Fortran does not build .Net (dotNet) applications whereas Silverfrost does.

I prefer building INTEL win32/win64 dlls/executables however sometimes have to link/work with dotNet type environments/other programs so you'll need that in mind to keep things working on both. I use Silverfrost with Visual Studio 2008 and Intel with Visual Studio 2010/2012to avoid any cross pollination between the two compilers.

Thanks for the heads up, we don't intend to do .net apps, life's complicated enough in win32!

K

OK, another issue (which I knew would be a problem...)

FTN95 has a series of "intrinsic" CORE functions that allow addresses to be converted to values (the reverse of LOC), thus:

REAL A

INTEGER IAD

IAD=LOC(A)

A=FCORE4(IAD)

From a brief scan of the help files, i'm guessing that TRANSFER is the equivalent function, but i thought i'd ask here first before doing loads of editing!

TIA

K

PS.  Reading that page more thoroughly, i'm not so sure TRANSFER on it's own does what I want - do I need to combine it with %VAL?

%VAL was a legacy extension (not widely supported) which accomplished what would be done with the value attribute in iso_c_binding.  I think general speculation on how those ftn95 intrinsics relate to standard Fortran would be out of place here; did you try the "official" Salford translation of fcore4 or compare it with what a Cray pointer would do?

http://forums.silverfrost.com/viewtopic.php?t=2480

Thanks for replying, but i don't follow.

that link says i should code up something in "c" - is that what you are recommending?

Also, i don't know what a "cray pointer" is, is it a dog that helps fresh water fishermen find their lobster pots :)?

K

Neither TRANSFER nor %VAL will be of direct use here. TRANSFER simply moves bits from one argument to the other, and %VAL is usable only in the actual argument list of a non-intrinsic procedure call.

There are a couple of ways to do this, one that is non-standard but a bit easier, the other which is standard but more complex. But first I will point out a bit of danger in your use of INTEGER to declare something that holds an address - this won't work when building a 64-bit application.

There are several different approaches you could take, some standard, some extensions. The snippet of code you showed doesn't make a lot of sense, as you're effectively assigning A to A. So that I can advise you better, can you give a better example? Are you required to work with integer addresses or would use of Fortran standard pointers be acceptable? What is the context of this code?

Steve - Intel Developer Support

Hi Steve,

here's a simple example that, in FTN95 sets B=A:

  PROGRAM TEST
 
  REAL*4 A,B
  INTEGER*4 IAD
 
  A=2.4
  IAD=LOC(A)
  B=FCORE4(IAD)
 
  WRITE(*,*)"A,B=",A,B  
 
  END             

the context is that, for historical reasons, our code passes the location (IAD) between functions and the CORE routines retrieve the stored values.  Rewriting that main functional code in "another way" will be impractical...

K

Ok. Here's the simplest conversion:

PROGRAM TEST
REAL*4 A,B
POINTER (IAD, B)
A = 2.4
IAD = LOC(A)
B = A
WRITE(*,*) "A,B",A,B
END

The POINTER statement with parentheses is an "integer pointer" declaration, not to be confused with the Fortran standard POINTER feature. Inside the parentheses are two names - the first is an integer variable called "pointer" that can hold an address, and it is automatically declared as the right integer kind if not already declared. The second is called the "pointee". It is a variable of any type whose location is taken from whatever value is in its associated pointer. Referencing the pointee is the equivalent of using the FCORE function on the pointer, if that makes sense.

Steve - Intel Developer Support

ok, thanks, i'll see how implementable that is with our existing function calls.

K

You could probably write your own function FCORE4 and make it really easy. Something like this:

function FCORE4 (IADDR)
real*4 FCORE4, X
integer(int_ptr_kind()) :: IADDR
pointer (P, X)
P = IADDR
FCORE4 = X
return
end function FCORE4

Repeat similar for functions that return other types.

Steve - Intel Developer Support

looks like it's a fix!

thank you!

K

Oh, if you have functions that return other types, you'll need to declare them as the appropriate type in the caller if the implicit typing is wrong.

Steve - Intel Developer Support

As you have probably found out if you tried Steve's function FCORE4, the second line should have FCORE4 instead of FCORE.  If you are unfamiliar with Cray pointers, the function can be a little mystefying, but it translates to efficient machine code. On Linux x64, the instructions are (GNU format):

    mov    (%rdi),%rax
    movss  (%rax),%xmm0
    ret

On Windows 64, you would see %rcx instead of %rdi in the first instruction.

I preffered the " a dog that helps fresh water fishermen find their lobster pots" version. :-)

I edited the post - thanks for the correction, though due to the miracles of implicit rules, it would have worked anyway...

Steve - Intel Developer Support

Steve,

Does the following change to your TEST show what is implied by the POINTER (IAD,B) statement ?

PROGRAM TEST
 REAL*4 A,B
 POINTER (IAD, B) 
!
 IAD = LOC(A)
 A = 2.4
 WRITE(*,*) "A,B",A,B
 B = 3.2
 WRITE(*,*) "A,B",A,B
 A = 4.3
 WRITE(*,*) "A,B",A,B
 END 

Yes - that's right.

Steve - Intel Developer Support

Some slight "twists"...

In FTN95 the following works:

PROGRAM TEST 
  
  REAL*4 A(2),B
  INTEGER*4 IAD
 
  a = 0.0
  IAD=LOC(A)
    FCORE4(IAD)    =  2.4   ! equivalent to A(1)=2.4
    FCORE4(IAD+4)    =  4.7 ! equivalent to A(2)=4.7
  
  CALL REPORT(FCORE4(IAD),2) ! These two calls are equivalent
  CALL REPORT(A,2) 
  
END     
     
SUBROUTINE REPORT(A,N)
  REAL  A(n)            
 WRITE(*,*)"A(1,2)=",A(1),A(2)
 END 

that is, using the FCORE4 in two ways:

1 On the lhs of an assignment

2 to "cast" an address to an array which is passed to another routine.

Any ideas on how to do this in IVF?

K

Your tiny example does not indicate what the programming constraints are. The subroutine has no need for non-standard code, so it is not part of the discussion. Perhaps,  the constraint is that you need to pass a real array to the subroutine, but you will only know the address of the array at run time, with that address possibly generated by code for which you do not have source. Here is code that illustrates that scenario, handled using a Cray pointer. The argument of Subroutine PREPO is an integer which is, presumably, the address of an array.

PROGRAM TEST 
 IMPLICIT NONE
 REAL*4 A(2)
 INTEGER (int_ptr_kind()) :: APTR
DATA A/3.0,5.0/
 APTR=LOC(A)
 CALL PREPO(APTR)
END
SUBROUTINE PREPO(IBP)
 IMPLICIT NONE
 REAL*4 X(2)
 POINTER(IBP,X)
 CALL REPORT(X,2)
RETURN
END 
SUBROUTINE REPORT(A,N)
 IMPLICIT NONE
 INTEGER N
 REAL A(N)
WRITE(*,*)"A(1,2)=",A(1),A(2)
RETURN
END

thanks, some more detail is perhaps needed, but i wanted to keep it simple for illustrative purposes.

the existing code does a lot of:

1 grab a memory buffer using the equivalent of "malloc"

2 populate that buffer using subroutines that make calls such as:FCORE4(IAD+4)    = X

3 passes the buffer address to a subroutine where it is treated as an array

i realise that this is not a "sensible" way to do things nowadays, but it's legacy code that originally was written in F77 so structures and other "new fangled" capabilities weren't available.

K

I think that the suggested code that I gave above fits your specifications. In fact, I took out the main program, and called the remaining subroutines with the following C main program, which allocates the array using malloc() and calls the Fortran subroutine, passing the pointer by address, and found that things work correctly. (Windows 32-bit code).

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]){
extern void PREPO(float **);
float *fptr=(float *)malloc(2*sizeof(float));
fptr[0]=15.0; fptr[1]=20.0;
PREPO(&fptr);
}

thanks, i'll take another look, but i think that, to match up with my needs, the call to REPORT needs to be outside the call to PREPO...

In other words, PREPO shouldn't need to know about the array X

k

OK, taking the comments above and looking at the old VAX code i had squirrelled away, tells me that:

  1. passing FCORE4(IAD) to a subroutine and expecting that subroutine to treat it as an array, probably won't work
  2. using the syntax "FCORE4(IAD)=X" won't work either

so...

  1. I have to pass the IAD directly to the subroutine, which then allocates an array and uses the FCORE4 function to populate it
  2. i have to replace "FCORE4(IAD)=X" with an old VAX trick using %VAL.

the attached illustrates both techniques, and also uses the VAX trick to illustrate with "get_r4" an alternative to the FCORE4 function...

any comments/recommendations/speedups welcomed before I start recoding my source?

K

Anexos: 

AnexoTamanho
Download new1.for1.43 KB

Another question, if I may...

it crossed my mind that, if I build a FTN95 DLL, I should be able to make calls to it from an IVF main program.  I've built a .LIB (attached) via the FTN95 linker but i'm struggling to work out how to link it with my IVF main.  I can't use VS at the moment (some annoying licence issue!) so i'm trying to use "link" directly from the command line:

link new2.obj new1.lib

but i can't get it to link.  i'm sure there's an obvious switch missing, but the help files seem to assume a pre-existing level of expertise in its use that I don't have...

TIA

K

Anexos: 

AnexoTamanho
Download new1.zip4.7 KB

If you are going to link objects produced by two compilers, you not only reduce portability considerably, but you need to be ready to establish correct subroutine linkage at the machine level. Secondly, the DLL that you built using FTN95 is dependent on SALFLIBC.DLL, so you will need to see if you are allowed to deplot/redistribute it under your license terms.

For string arguments, Intel Fortran and Salford Fortran pass the extra hidden length arguments by value. Therefore, for your example to work, you need not pass any extra arguments.

It is trivial to get your example to work, but it is rather pointless to do so since New1.f90 does not depend on any Fortran extensions that are provided by FTN95 but not by IFort. Try constructing another example in which, for instance, the DLL uses FTN95 features that you need such as FCore4().

The main problem here is that your syntax for the ATTRIBUTES directive is wrong - there should be a colon between ALIAS and '_TEST'. However, as far as I can see, you don't need the directive at all. There's no evidence that the TEST routine is STDCALL - if it isn't, then just remove the directive. I also suggest that you use ifort to do the linking, which is what the help describes.  If you take out the directive, then this works:

ifort new2.f90 new1.lib

The DLLIMPORT is optional for procedures.

Steve - Intel Developer Support

Great, thanks Steve.  Shouldn't the compiler have spotted my syntactical error?

Interestingly, it seems that STDCALL isn't necessary when calling FTN95 from IVF, but is necessary (for passing strings) when calling IVF from FTN95!  Go figure!

K

The compiler did catch the error when I compiled it. You didn't say what errors you got. 

new2.f90(5): remark #5144: Invalid character_kind_parameter. No underscore
!DEC$ ATTRIBUTES DLLIMPORT, STDCALL, ALIAS '_TEST' :: test
---------------------------------------------------^
new2.f90(5): remark #5082: Directive ignored - Syntax error, found CHARACTER_CONSTANT '_TEST' when expecting one of: ( * ) :: , <END-OF-STATEMENT> ; . % (/ + -[ : ] /) . ** / // ...
!DEC$ ATTRIBUTES DLLIMPORT, STDCALL, ALIAS '_TEST' :: test
-------------------------------------------^

STDCALL would be needed for calling CVF, but not IVF. String lengths are also passed differently between CVF and IVF.

Steve - Intel Developer Support

Citação:

mecej4 escreveu:

If you are going to link objects produced by two compilers, you not only reduce portability considerably, but you need to be ready to establish correct subroutine linkage at the machine level. Secondly, the DLL that you built using FTN95 is dependent on SALFLIBC.DLL, so you will need to see if you are allowed to deplot/redistribute it under your license terms.

For string arguments, Intel Fortran and Salford Fortran pass the extra hidden length arguments by value. Therefore, for your example to work, you need not pass any extra arguments.

It is trivial to get your example to work, but it is rather pointless to do so since New1.f90 does not depend on any Fortran extensions that are provided by FTN95 but not by IFort. Try constructing another example in which, for instance, the DLL uses FTN95 features that you need such as FCore4().

that use of the FTN95 FCORE4 routine is going to be my next test, but i wanted to establish the principle first...

K

Citação:

Steve Lionel (Intel) escreveu:

The compiler did catch the error when I compiled it. You didn't say what errors you got. 

new2.f90(5): remark #5144: Invalid character_kind_parameter. No underscore
!DEC$ ATTRIBUTES DLLIMPORT, STDCALL, ALIAS '_TEST' :: test
---------------------------------------------------^
new2.f90(5): remark #5082: Directive ignored - Syntax error, found CHARACTER_CONSTANT '_TEST' when expecting one of: ( * ) :: , <END-OF-STATEMENT> ; . % (/ + -[ : ] /) . ** / // ...
!DEC$ ATTRIBUTES DLLIMPORT, STDCALL, ALIAS '_TEST' :: test
-------------------------------------------^

STDCALL would be needed for calling CVF, but not IVF. String lengths are also passed differently between CVF and IVF.

strange!  I must have just ignored the "remark" (or what I had compiled wasn't what I uploaded!!! :o)

K

Fortran 2008 adds the "feature" of having a reference to a function returning a pointer on the left side of an assignment statement, though there has been some discussion on the standards committee that this may have been a bad idea. Intel Fortran doesn't support it at this time.

Steve - Intel Developer Support

sooo...

if the idea of linking against an FTN95 DLL is going to fly (which i think it will given a fair wind!), i need to create a "windows" executable.  So i tried:

C:intel_vswlib>ifort /winapp new2.f90 llib.lib
Intel(R) Visual Fortran Compiler XE for applications running on IA-32, Version 1
3.1.2.190 Build 20130514
Copyright (C) 1985-2013 Intel Corporation.  All rights reserved.
Microsoft (R) Incremental Linker Version 11.00.50727.1
Copyright (C) Microsoft Corporation.  All rights reserved.
-out:new2.exe
-subsystem:windows
new2.obj
llib.lib
LIBCMT.lib(wincrt0.obj) : error LNK2019: unresolved external symbol _WinMain@16
referenced in function ___tmainCRTStartup
new2.exe : fatal error LNK1120: 1 unresolved externals

How do i fix it?

K

Take off /winapp.

Steve - Intel Developer Support

aah, but the DLL i'm linking to has some (lots) of windows functions that i'd like to test to see if thay work from an IVF main.  Am I right in assuming i need an event loop handler in my IVF main?  if so, what do i need to call?

K

Ok. If it IS a Windows application with message loops, etc., then you need a WinMain entry point and a message loop. If you create a Windowing Application project in Visual Studio, you can get sample code that includes this (and other things you can probably remove). There are also a number of Windows application samples provided.

Simply calling Windows API routines, on its own, doesn't need this, but anything that interacts with windows probably does.

Steve - Intel Developer Support

unfortunately, I can't run VS.  I had previously evaluated VS 2012 but the evaluation period has ended.  I was told that IVF included a VS "shell" but despite repeated attempts to reinstall IVF, I still get told that my VS licence has lapsed and it asks for a product key before it will let me in! :(

I have logged a support ticket and been told to uninstall the compiler and VS then reinstall the compiler...here goes...

K

Here is a sample Windowing application project.  You can look at the source files it contains.

Anexos: 

AnexoTamanho
Download winapp1.zip18.51 KB
Steve - Intel Developer Support

Thanks Steve, i now have VS 2010 working but it seems it can't read your file:

"winapp1.vfproj cannot be opened because its project type (.vfproj) is not supported by this version...etc"

K

Perhaps you did not reinstall Fortran.

Steve - Intel Developer Support

Páginas

Deixar um comentário

Faça login para adicionar um comentário. Não é membro? Inscreva-se hoje mesmo!