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

IFX Internal Compiler Error

Mike33
Beginner
1,329 Views

I'm using the Intel Fortran Compiler (IFX) version 2023.2.1 and I'm unable to compile a section of code that has a very long if...else if...else statement (approximately 11,000) cases.

 

The same statement compiles using the Intel Fortran Classic Compiler (IFORT) version 2021.6.0 in Debug mode.

 

The error message issued by IFX is:

xfortcom: Fatal: There has been an internal compiler error (C00000FD).

 

I was hoping to develop a workaround for this issue rather than taking the time to refactor the code. 

 

Labels (1)
0 Kudos
1 Solution
andrew_4619
Honored Contributor II
1,103 Views
program longprog

   implicit none

   character (len =  :: stringval
   real (kind = 8), dimension(200) :: dblarray
   real (kind = 8), dimension(16384,200) :: x
   logical :: finish

   finish = .true.
   if (stringval == "X1") then
      dblarray = x(1,:)
   else if (stringval == "X2") then
      dblarray = x(2,:)
   else if (stringval == "X3") then
      dblarray = x(3,:)
   else if (stringval == "X4") then
      dblarray = x(4,:)
   else if (stringval == "X5") then
      dblarray = x(5,:)
   else
       finish = .false.
   endif
   if (finish) goto 1000 ! jump to end of ifs
   finish = .true.
   if (stringval == "X6") then
      dblarray = x(6,:)
   else if (stringval == "X7") then
      dblarray = x(7,:)

A minor tweak such as the code inserted at lines 21 to 25 would make the problem go away if you do that every 8000 cases. I will make no analysis of the  algorithm you are using other than to say it causes a dull pain between the ears. There are a list of parameters that  limit the compiler, if you exceed one of them it is time to reappraise what you are doing IMO.

 

 

 

 

View solution in original post

0 Kudos
19 Replies
Steve_Lionel
Honored Contributor III
1,313 Views

You'll need to provide a test case that demonstrates the problem. It's impossible to know what causes a particular error without one.

Mike33
Beginner
1,271 Views

I've attached a trivially simple and silly program that demonstrates the error.  In the real program, there isn't a predictable relationship between the string value and the double array it is associated with.

Additionally, I believe that the mapping was implemented this way because it facilitates automatic code generation with data from two independent platforms that is frequently updated.

C:\>ifx longprog.f90
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2023.2.0 Build 20230627
Copyright (C) 1985-2023 Intel Corporation. All rights reserved.

xfortcom: Fatal: There has been an internal compiler error (C00000FD).
compilation aborted for longprog.f90 (code 1)

 

There seems to be an arbitrary compiler limit for the number of cases in an if...else if...else block because it will compile for blocks with less cases.  I like to see that case limit be north of 50,000 - perhaps 2^16.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,258 Views

>>...

>> real (kind = 8), dimension(16,200) :: x

>>...

>>dblarray = x(17,:) *** array out of bounds

>>...

>>dblarray = x(18,:) *** array out of bounds

>>...

>>dblarray = x(16384,:) *** array out of bounds

Jim Dempsey

 

0 Kudos
Mike33
Beginner
1,237 Views

Thanks Jim!  I dimensioned x properly in the updated version below, but I'm getting the same error.

real (kind = 8), dimension(16384,200) :: x

 

I've also determined that if I cut the number of cases back to 8,016 or less, it will compile.

0 Kudos
Ron_Green
Moderator
1,229 Views

I do see the internal compiler error.  However, ....

Do you honestly have a real world program doing this algorithm?  Or was this a contrived test to check limits of a compiler?  If this is from real code then I'm frankly horrified.  I would assume this was machine generated, or you had a really patient intern writing this. 

What you really want to do is something like this sample.  Obviously the stringval of 'X42' is contrived just to test the logic of this solution.  In reality I assume this is inside a subroutine and x, dblarray, and stringval are all passed as arguments. 

program longprog

   implicit none

   integer, parameter :: X_DIM1 = 16384
   integer, parameter :: X_DIM2 = 200
   integer, parameter :: STRINGVAL_LEN = 8

   character (len = STRINGVAL_LEN) :: stringval
   character (len = STRINGVAL_LEN - 1 ) :: trimmed_stringval
   integer :: x_dim1_indx

   real (kind = 8), dimension(X_DIM2) :: dblarray
   real (kind = 8), dimension(X_DIM1,X_DIM2) :: x

   !...this is artificial.  stringval is probably read in from a file
   stringval = 'X42'

   if ( stringval(1:1) .ne. 'X' ) then
     write(*,*) 'bad initial character in stringval: ', stringval(1:1)
     stop
   end if

   trimmed_stringval = stringval(2:)
   read( trim(trimmed_stringval),'(I)') x_dim1_indx

   !...test that the index is in bounds
   if ( (x_dim1_indx <= 0 ) .OR. (x_dim1_indx > X_DIM1 ) ) then
    write(*,*) 'invalid index. stringval and x_dim1_indx ', stringval, x_dim1_indx
    stop
   end if 

  !... do the assignment
  dblarray = x(x_dim1_indx,:)

end program longprog

I have to be convinced to write up a bug report for something so obtuse.  Can you justify our effort to fix this instead of you rewriting this into something that won't make any programmer go screaming and turning to C++?   

0 Kudos
Mike33
Beginner
1,196 Views

Thanks Ron! Your sample code is great, but it's a little too specialized to the example program I posted.  The real world  code that I have converts a string input to an associated double array as output.  The string passed in and the name of the double array returned are not related in any predictable way.  I could reimplement this code as a hash table or some other data structure, but I'm a little upset that the code compiles and runs just fine using ifort but does not with ifx.  I was assuming that there is some parameter in ifx that could be easily changed to handle an if...else if...else statement which has more than 8,016 cases just like ifort. Is that not the case? 

0 Kudos
andrew_4619
Honored Contributor II
1,104 Views
program longprog

   implicit none

   character (len =  :: stringval
   real (kind = 8), dimension(200) :: dblarray
   real (kind = 8), dimension(16384,200) :: x
   logical :: finish

   finish = .true.
   if (stringval == "X1") then
      dblarray = x(1,:)
   else if (stringval == "X2") then
      dblarray = x(2,:)
   else if (stringval == "X3") then
      dblarray = x(3,:)
   else if (stringval == "X4") then
      dblarray = x(4,:)
   else if (stringval == "X5") then
      dblarray = x(5,:)
   else
       finish = .false.
   endif
   if (finish) goto 1000 ! jump to end of ifs
   finish = .true.
   if (stringval == "X6") then
      dblarray = x(6,:)
   else if (stringval == "X7") then
      dblarray = x(7,:)

A minor tweak such as the code inserted at lines 21 to 25 would make the problem go away if you do that every 8000 cases. I will make no analysis of the  algorithm you are using other than to say it causes a dull pain between the ears. There are a list of parameters that  limit the compiler, if you exceed one of them it is time to reappraise what you are doing IMO.

 

 

 

 

0 Kudos
Mike33
Beginner
1,071 Views

Thanks Andrew! I took a look at the evolution of this code which was originally implemented in 2010 with a smallish number of cases but then increased substantially to the point that a similar approach had to be taken in 2017 to accommodate the compiler limit in ifort which appears to be around 12,000 cases, so it should be straightforward now to refactor it into blocks of 8,000 to accommodate the ifx limit.  It is a little bit surprising that the limit in ifx is less than what it was in ifort.

0 Kudos
mecej4
Honored Contributor III
1,080 Views

An additional argument against using a cascade of 16384 IF (str == cstr(n)) THEN .. blocks is that, on average, if str is equally likely to be one of the 16384 values, 8192 string comparisons have to be made before a match is found. If str does not match any, then 16384 comparisons have to be made. On the other hand, if one maintained a sorted cstr array, a binary search would require just 14 comparisons on average. Such a situation should motivate a thorough investigation of patterns in the cstr array, however elusive they might be.

If no pattern can be found, it would still be a far better solution to write code along the lines of

 

integer, parameter :: NS = 16384
character(len=6)   :: cstr(NS), str
logical :: begin = .true.
...
if (begin) then
   read (iunit,'(A6)') (cstr(i), i = 1, NS)
   begin = .false.
end if
...
imatch = 0
do i = 1, NS
   if (str .eq. cstr(i)) then
      imatch = i
      exit
   end if
end do

 

0 Kudos
Mike33
Beginner
1,061 Views

Thank you for the thoughtful analysis. My long-term plan is to put all of the arrays into a binary tree or hash table with the string as the Key and (a pointer to) the array as the Value. Is there anything comparable to the Java Collections framework TreeSet (Java Platform SE 8 ) (oracle.com) or HashMap (Java Platform SE 8 ) (oracle.com) available for Intel Fortran?  

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,071 Views

@mecej4 suggestion might be a better choice.

This said, does the compiler accept SELECT CASE  format?

I made the edits for you but haven't compiled the source code.

Jim Dempsey

0 Kudos
Mike33
Beginner
1,036 Views

Thanks Jim! The modified code with a select...case instead of if..else did compile, but it took about 15 minutes and xfortcom required about 700 MB of RAM at its peak.  This really surprises me because I would have assumed the compiler generated code would just be a super long sequence of compare and branch instructions.  Is there some sort of "optimization" algorithm running on the backend?

0 Kudos
andrew_4619
Honored Contributor II
1,008 Views

I believe select...case has quite a bit of optimisations and may lead to lookup tables or other methods if large rather than a direct brute force construct. The rules of select make this more doable.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,070 Views

Also, IIF your code is really using "Xnnn" format and additionally using the "nnn" as an index into the dblarray, then you can use in internal file read to converth the "nnn" from text to integer.

read(trim(stringval(2:)),'(I)') idx

dblarray = x(idx,:)

 

Jim Dempsey

0 Kudos
Mike33
Beginner
1,033 Views

I wish this were the case, but in the real code there is no relationship between the stringval and the index into the array.  It was just easier for me to create that sample program with a loop and use the index for the variable names.

0 Kudos
Ron_Green
Moderator
967 Views

I spoke to the front-end team on this.  They want to have a look.  I'm opening a bug report with the test case the crashes.

0 Kudos
Mike33
Beginner
920 Views

Thanks Ron!  I appreciate your help with this issue. I've implemented Andrew's workaround solution by breaking the if...else statement up into blocks of 8,000 cases or less.  I've also turned off all compiler optimizations. My program now compiles and runs within acceptable limits for ifx, so don't waste too much developer time on my account.  However, it would be great if you have the resources to investigate all of the findings in this thread and improve what the Intel Fortran compiler is doing with if...else and select case statements that are ridiculously large.  

0 Kudos
Ron_Green
Moderator
703 Views

The bug ID is CMPLRLLVM-58661.  One of the developers was interested in seeing this error.  If it's a simple fix, isolated to a simple malloc or a stand-alone variable or structure used in an isolated part of the code with low risk, we'll increase it.  But if it's in a complex struct used all over the code and hence high risk for causing regressions we'll not fix it.  It is a curious one, and we do want to see if it's as simple as a malloc change. 

 

thanks for sending this to us.  It's an unusual one, and nothing I've seen since joining this team in 2005.  I like these odd cases. 

 

ron

0 Kudos
jimdempseyatthecove
Honored Contributor III
590 Views

Here is an alternative coding method

do ! omit do/enddo if using return
  if (stringval == "X1") then
      dblarray = x(1,:)
      exit ! or return
   endif
   if (stringval == "X2") then
      dblarray = x(2,:)
      exit ! or return
   endif
   ...
end do

I think @mecej4 binary search method is better

or a hash table with collision detection/handling may be better yet.

You will have to design the appropriate hash function to reduce the number of collisions as well as minimize the table size.

 

Jim Dempsey

 

0 Kudos
Reply