- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim's fix works.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page