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

Disabling use of libimf and resolving missing math functions

Towie__Ewan
New Contributor I
2,312 Views

Hi there,

I'm currently working on a project to move away from use of the Intel math library (libimf) on a Intel Fortran compiled codebase. The aim is to switch to an open-source math library as this allows us to have (better) results consistency across various CPU manufacturers and OS's.

I'm able to integrate the alternate math library to the Intel Fortran compilation. However, as soon as I disable the linking of libimf through the link option '-no-intel-lib=libimf', I get a lot of linking errors for undefined math functions.

error: undefined reference to '__powr8i4'
error: undefined reference to 'f_pow2i'
error: undefined reference to 'pow2o3'
error: undefined reference to '__powq'
error: undefined reference to '__sqrtq'

I presume that the Intel Fortran compiler assumes use of libimf and therefore introduces such optimised math functions.

Is there a way to modify the compilation to avoid pulling in libimf math functions?

Or, can you tell me where I can find the libimf header file so I can reproduce such functions for my project?

Thanks,

Ewan

Labels (1)
0 Kudos
11 Replies
jimdempseyatthecove
Honored Contributor III
2,264 Views

Link with libimf, and place Debug break points at those functions. Then look at the call stack to see if the issue resides with the code you compile or with a dependent library that you do not compile.

If in your code, you should be able to reconstruct it to not make these calls.

If in 3rd party library, then you may be out of luck...

... unless you write a shell function to convert the SIMD arguments into scalars and call your preferred function (for each lane in the SIMD register(s)), then return the result(s) back into SIMD registers.

 

Jim Dempsey

0 Kudos
Towie__Ewan
New Contributor I
2,255 Views

I've probably not been clear enough in my original post, but I'm not calling any of these functions and it's the compiler itself that is somehow inserting these function calls.

For example, the Fortran code that creates the call to 'f_pow2i' is 'IT   = 2**(J-2)' where IT and J are integers.

Or, the call to  'y = x**(2.d0/3.d0)' where x and y are double precision creates a call to 'pow2o3'.

This is all beyond my control, as far as I am aware. I've trawled through the compiler manual, but information on libimf and what it provides in terms of an API is completely neglected.

 

Ewan

0 Kudos
JohnNichols
Valued Contributor III
2,236 Views

Try rewriting your equations so there are no powers, use something like logs. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,194 Views

This may seem odd, but it may work for the instances of **

 

Create a generic function, call the interface it my_pow

And supply functions to match the various permutations of arguments:

 

integer, integer

real,real

real, integer

double, real

double, double

double, integer

and possibly real,double

then fix all instances of ** to look like

! was IT   = 2**(J-2)

IT = my_pow(2, (J-2))

 

Should be relatively easy.

 

Jim Dempsey

 

0 Kudos
Steve_Lionel
Honored Contributor III
2,216 Views

The only way you're going to get there is if, as Jim suggests, you write your own wrappers for these libimf functions. Unfortunately, they are not documented. There is no option to substitute a different set of library calls.

0 Kudos
Towie__Ewan
New Contributor I
2,097 Views

I did suspect as much, but I though it was a good question for the community!

 

Although the other suggestions are pragmatic, my aim here is to provide a solution that avoids modifying the project code. So I'll look to provide some wrapper somewhere that directs the libimf functions back to some 'generic' libm calls.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,078 Views

Outline of what you need to do:

Build candidate program (x64 I presume) and set a break point.

jimdempseyatthecove_0-1697205379057.png

Open Dissassembly window:

jimdempseyatthecove_1-1697205449422.png

In this example (f_pow2i), the arguments are integer (other functions will have different argument types). 

On the call, the two arguments are passed in edx (J-1) and ecx (not sure why this is 1 and not 2).

Add an Intel icx Static Library (and make the Fortran Project depend on it).

jimdempseyatthecove_3-1697209652924.png

With the breakpoints set as above, you can see the values of the arguments as discussed earlier.

Now that you have the two arguments in hand, you can construct the results as you wish.

 

Note, I did not have to use the ink option '-no-intel-lib=libimf'.

This should get you going.

 

Jim Dempsey

 

0 Kudos
Towie__Ewan
New Contributor I
2,073 Views

Thanks Jim for such an in-depth answer!

I've started writing a wrapper in C++ similar to your 'imf.cpp' to direct the libimf calls back to <cmath> standard calls. I'm hoping then, and I need to check, that the open-source math library I then subsequently link will be picked up. The open-source math library already overloads the standard C/C++ libm functions.

What I hadn't banked on was the intrinsic support for quad precision in Fortran, and seemingly in libimf. Here I'm having to direct the math functions to the <quadmath.h> library and hope that there isn't a big difference in code optimisation.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,054 Views

>>Here I'm having to direct the math functions to the <quadmath.h> library and hope that there isn't a big difference in code optimisation.

 

You may also have quality of returned data.

I would suggest finding a Fortran Source that calculates rational powers. Then compare the results with what you get from quadmath.h

 

From: https://stackoverflow.com/questions/2882706/how-can-i-write-a-power-function-myself

There is a C example (for double) that you can adapt to Fortran using quad precision:

#define MAX_DELTA_DOUBLE 1.0E-15
#define EULERS_NUMBER 2.718281828459045

double MathAbs_Double (double x) {
    return ((x >= 0) ? x : -x);
}

int MathAbs_Int (int x) {
    return ((x >= 0) ? x : -x);
}

double MathPow_Double_Int(double x, int n) {
    double ret;
    if ((x == 1.0) || (n == 1)) {
        ret = x;
    } else if (n < 0) {
        ret = 1.0 / MathPow_Double_Int(x, -n);
    } else {
        ret = 1.0;
        while (n--) {
            ret *= x;
        }
    }
    return (ret);
}

double MathLn_Double(double x) {
    double ret = 0.0, d;
    if (x > 0) {
        int n = 0;
        do {
            int a = 2 * n + 1;
            d = (1.0 / a) * MathPow_Double_Int((x - 1) / (x + 1), a);
            ret += d;
            n++;
        } while (MathAbs_Double(d) > MAX_DELTA_DOUBLE);
    } else {
        printf("\nerror: x < 0 in ln(x)\n");
        exit(-1);
    }
    return (ret * 2);
}

double MathExp_Double(double x) {
    double ret;
    if (x == 1.0) {
        ret = EULERS_NUMBER;
    } else if (x < 0) {
        ret = 1.0 / MathExp_Double(-x);
    } else {
        int n = 2;
        double d;
        ret = 1.0 + x;
        do {
            d = x;
            for (int i = 2; i <= n; i++) {
                d *= x / i;
            }
            ret += d;
            n++;
        } while (d > MAX_DELTA_DOUBLE);
    }
    return (ret);
}

double MathPow_Double_Double(double x, double a) {
    double ret;
    if ((x == 1.0) || (a == 1.0)) {
        ret = x;
    } else if (a < 0) {
        ret = 1.0 / MathPow_Double_Double(x, -a);
    } else {
        ret = MathExp_Double(a * MathLn_Double(x));
    }
    return (ret);
}

Jim Dempsey

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,069 Views

And pow203 (power of 2 over 3):

jimdempseyatthecove_1-1697211526062.png

 

 

The __asm syntax is strange (I had to look up examples), but once you get one or two functions written, the remainder will be much of the same.

 

Jim Dempsey

0 Kudos
Towie__Ewan
New Contributor I
1,631 Views

I've spent more time on this project recently and made some breakthroughs on how to disable the use of the Intel Math library (libimf).

I've figured that the use of the '-fp-model' compiler argument strongly controls which libimf specific optimised math routines are called. By simply telling ifort to use the '-fp-model strict' it seems to push the compiler to use mostly standard libm/math.h math function calls. (Note that I encountered very odd behaviour with other '-fp-model' parameters and alternative math libraries; it seems that the compiler makes additional assumptions regarding libimf).

There is still a requirement to write a wrapper object to capture any libimf calls that are implicitly included by the Intel compiler. These are mostly a set of power functions that have an integer exponent. The 'standard' libm will usually promote these all to pow<double,double> calls so overloading these with some custom/optimised integer power code is probably for the greater good.

Finally, if linking with the Intel compiler, then use of the '-no-intel-lib=libimf' argument to force it to not auto-link the libimf library is the final stage.

 

After all this, I've been able to manipulate Intel Fortran compiled code to use an alternative math library of my choice. The final binaries, due to linking Intel Fortran compiler library (libifcore) will still pull in libimf, but this at least is a 3rd-party pull-in and appears after my preferential math library (and hopefully shouldn't interfere with my code).

 

In short, this is possible but messy and ultimately you still have to provide a copy of libimf somewhere to get it all to work!

0 Kudos
Reply