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

Issue with Fortran-C interoperability with -O3?

aidan_c_
Beginner
625 Views

Hi,

I'm writing some FORTRAN code that calls a C library, and having issues when I compile the code with -O3. The code that is breaking is this:

Subroutine create_qsched_tasks(nr_threads)
Use, Intrinsic :: ISO_C_BINDING
Use cell_list_module
  Use quicksched
Implicit None

Integer, Intent(In) :: nr_threads
Integer(Kind=C_INT), Dimension(1:number_cells) :: cell_res, sorts
Integer(Kind=C_INT) :: i, j ,k, id, p, id2, temp
Integer(Kind=C_INT), Target :: data(0:10)
Type(C_PTR) :: dat_ptr

dat_ptr = C_LOC(data(0))

qsched = f_qsched_create()
call qsched_init(qsched,Int(nr_threads, C_INT), 0)
do i=1,number_cells
  cell_res(i) = qsched_addres(qsched, qsched_owner_none, qsched_res_none)
  print *, i
  data(0) = i
  sorts(i) = qsched_addtask(qsched, type_sort, 0, dat_ptr, int(c_sizeof(type_sort), C_INT), cell_list(i)%cell_count)
  call qsched_addlock(qsched, sorts(i), cell_res(i))
end do

 

The qsched_addtask function runs some code, but also contains 

 printf("data is %i, size is %i\n", *(int*)data, data_size);

where data is a void* and is argument 4, and data_size is argument 5. The output from this code is:

1
data is 0, size is 4
2
data is 0, size is 4
3
data is 0, size is 4

However with -O2 I get:

1
data is 1, size is 4
2
data is 2, size is 4
3
data is 3, size is 4
 

The function itself seems to work fine, as following this code I have another statement:

do i=0, x_cells+1
  do j=0, y_cells+1
    do k=0, z_cells+1
      id = 1+i+(x_cells+2)*(j+(y_cells+2)*k)
        data(0) = id
        temp = qsched_addtask(qsched, type_vdw_self, 0, dat_ptr, int(c_sizeof(type_sort),C_INT), cell_list(id)%cell_count)
        call qsched_addlock(qsched, temp, cell_res(id))
        call qsched_addunlock(qsched, sorts(id), temp)
...

which functions completely as expected, and the value stored in data(0) is passed correctly to the C library.

The interoperable function in question is as follows:

    Integer(Kind=C_INT) Function qsched_addtask(s, types, flags, data, data_size, cost) BIND(C)
      Use, Intrinsic :: ISO_C_BINDING
      Implicit None

      Type(C_PTR), VALUE :: s
      Integer(Kind=C_INT), Intent(In), VALUE :: types
      Integer(Kind=C_INT), Intent(In), VALUE :: flags 
      Type(C_PTR), VALUE :: data
      Integer(Kind=C_INT), Intent(In), VALUE :: data_size
      Integer(Kind=C_INT), Intent(In), VALUE :: cost

    End Function

Am I doing something wrong that means the compiler thinks it can optimise away the value stored in data(0) in the first case?

 

Thanks

Aidan Chalk

 

 

0 Kudos
1 Solution
Martyn_C_Intel
Employee
625 Views

If you compile with -assume dummy_aliases  (or -no-ansi-alias), the Fortran compiler will allow for the possibility that subroutine arguments might be aliased.

A fix has been found for the original issue, it will appear in a future compiler. Will try to post when that happens.

 

 

View solution in original post

0 Kudos
9 Replies
Laura_S_3
Beginner
626 Views

I am going to guess that the optimizer did not recognize the connection between "data(0)" and "dat_ptr" and so assessed the changes to data(0) to be of no consequence within the loop - data is not directly used within the loop, just set. After the loop, does "data(0)" happen to contain number_cells?

In case this is considered a bug instead of merely an optimizer short-coming, what version of Fortran are you using?

0 Kudos
aidan_c_
Beginner
626 Views

Hi Laura

I added a print after the loop for data(0) and as you expected it output " end of loop data is 1000"

The compiler tells me I'm using:

-bash-4.1$ ifort -v
ifort version 17.0.2

which according to the sysadmin is from intel 17.2.050 release.

In terms of Fortran version the code is FORTRAN 90 other than the 2003 extensions used for the Fortran C interoperability I think.

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
626 Views

Fortran has anti-aliasing rules. Try:

data(0) = id
temp = qsched_addtask(qsched, type_vdw_self, 0, C_LOC(data(0)), int(c_sizeof(type_sort),C_INT), cell_list(id)%cell_count)

Jim Dempsey

0 Kudos
Laura_S_3
Beginner
626 Views

Hi Aidan,

Hopefully, some of the experts have an elegant way to keep the optimizer from optimizing out the assignments to data(0) within the loop.

The only way I can think of is definitely not elegant ... Add another argument to your C function that is intent(InOut) and pass data(0) to the function. The function doesn't have to do anything with that variable. However, since the optimizer can't tell what the C function is doing, it should assume that data(0) does need to be properly set within the loop.

Good luck! That sort of issue is very annoying to have to deal with.

Laura

0 Kudos
Martyn_C_Intel
Employee
626 Views

Since DATA has the TARGET attribute, this looks like a bug to me.

I have constructed a small reproducer and escalated it to the compiler developers. We'll let you know what they say.

The issue seemed to result from the scalar replacement optimization. You may be able to work around it by disabling this optimization with -scalar-rep-  (this worked for my small test case). However, it's possible that the root cause is deeper, and that interoperable C_PTRs are not recognized or handled in the same way as Fortran pointers.

0 Kudos
aidan_c_
Beginner
626 Views

Jim's fix works.

0 Kudos
mecej4
Honored Contributor III
626 Views

aidan c. wrote:

Jim's fix works.

That is striking and impressive! The following question is a natural consequence.

Since Fortran and C have different aliasing rules regarding subprogram arguments, how do you tell the Fortran compiler that a BIND(C) external routine may be in violation of the Fortran rules, and to arrange the call (with arguments copied in/out, as needed, to anonymous actual arguments) to cope with aliasing.

In other words, the BIND(C) takes care of the interface, but that may be insufficient when Fortran expects standards compliance in the external routine, as the external C compiler probably knows nothing about Fortran rules.

0 Kudos
jimdempseyatthecove
Honored Contributor III
626 Views

mecej4,

IMHO, in this case, anti-aliasing issue is solely on the Fortran side. I do not believe this is a bug as such. While the compiler could potentially make the alias determination, this is not required by the standard. An alternative "fix" might be to attribute data_ptr as volatile. A second (better??) alternative might be to use the associate data_ptr=>data(0) ... end associate as opposed to using a pointer.

Jim Dempsey

0 Kudos
Martyn_C_Intel
Employee
626 Views

If you compile with -assume dummy_aliases  (or -no-ansi-alias), the Fortran compiler will allow for the possibility that subroutine arguments might be aliased.

A fix has been found for the original issue, it will appear in a future compiler. Will try to post when that happens.

 

 

0 Kudos
Reply