Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.
7956 Discussions

A possible bug found in ICC compiler with inline ASM

mengke_e_
Beginner
780 Views

I found a bug when using the inline ASM of Intel Parallel Studio XE 2015 Update 2 Composer Edition for C++ Windows. Since I'm not very familiar with inline ASM, I'm not sure if it is a bug.

#include <iostream>

using namespace std;

__forceinline void DoNothingWithMemory( float*const copyByValue )
{
    float* copyByValueAgain = copyByValue ; 
    /*
    As you see, the two var in this function, "copyByValueAgain" and "copyByValue", are copied by value. Therefore, even if the code block of inline asm below changes one of them, there's nothing to do with the var "p" in the main function. However, the fact is, the var "p" in the main function IS changed after executing the code block of inline asm below!
    */

     __asm__ __volatile__(

        "lea 4(%0),%0;" //In fact, nothing is done here. It's just a "lea", and has nothing to do with memory or pointer aliasing!
        :
        :"r"( copyByValueAgain )
        :
        );
}

int main()
{
    float a; //just a place holder
    float* const p=&a; // As "p" is "const", it's impossible to change and should always point to "&a".
    for(int i = 0; i < 999; ++i) {
        cout<<p<<endl; // However, if you take a look at the output of this instruction, you will find that "p" changes every each loop, and that's really weird.
        DoNothingWithMemory(p); 
    }
    system("PAUSE");
}

 

0 Kudos
1 Solution
Shenghong_G_Intel
780 Views

OK, I am clear about the issue now, in your case, copyByValueAgain is used as both input and output variable, you need to describe that to compiler so that it will not generate unexpected code.

You may refer to below link to know how to declare a variable in inline asm as both input and output.

http://stackoverflow.com/questions/15993934/extended-inline-assembly-same-variable-for-input-and-output

And the working code is as below:

# cat temp.cpp
#include <stdio.h>

void DoNothingWithMemory(float* const copyByValue )
{
    float* copyByValueAgain = copyByValue ;
    /*
 *     As you see, the two var in this function, "copyByValueAgain" and "copyByValue", are copied by value. Therefore, even if the code block of inline asm below changes one of them, there's nothing to do with the var "p" in the main function. However, the fact is, the var "p" in the main function IS changed after executing the code block of inline asm below!
 *         */

    __asm__ __volatile__(
        "lea 8(%0),%0;" //In fact, nothing is done here. It's just a "lea", and has nothing to do with memory or pointer aliasing!
        :"+r"(copyByValueAgain)   // CHANGES HERE!!!!!!!!!!!
        ://"r"( copyByValueAgain ) // CHANGES HERE!!!!!!!!!!!
        :
        );
}

int main()
{
    float a; //just a place holder
    float* const p=&a; // As "p" is "const", it's impossible to change and should always point to "&a".
    for(int i = 0; i < 5; ++i) {
        printf("%p\n", p); // However, if you take a look at the output of this instruction, you will find that "p" changes every each loop, and that's really weird.
        DoNothingWithMemory(p);
    }
    return 0;
}
# g++ temp.cpp -O3 && ./a.out
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
# icc temp.cpp -O3 && ./a.out
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
#

Thanks,

Shenghong

View solution in original post

0 Kudos
5 Replies
mengke_e_
Beginner
780 Views

P.S. In the case of "/O2"

0 Kudos
Shenghong_G_Intel
780 Views

I've reproduce the issue on Linux too. It seems like an optimization issue, which works with O1. I'll report to dev team to check.

Thanks,

Shenghong

0 Kudos
Shenghong_G_Intel
780 Views

oops....The same test case failed with g++ in optimization mode too.

# g++ temp.cpp -O1 && ./a.out
0x7fff33ed950c
0x7fff33ed9510
0x7fff33ed9514
0x7fff33ed9518
0x7fff33ed951c
#

Maybe it is not a bug (the result may be undefined), I'll take a closer look at the code and hope I can get a good explanation on the behavior of gcc/icc.

Thanks,

Shenghong

0 Kudos
Shenghong_G_Intel
781 Views

OK, I am clear about the issue now, in your case, copyByValueAgain is used as both input and output variable, you need to describe that to compiler so that it will not generate unexpected code.

You may refer to below link to know how to declare a variable in inline asm as both input and output.

http://stackoverflow.com/questions/15993934/extended-inline-assembly-same-variable-for-input-and-output

And the working code is as below:

# cat temp.cpp
#include <stdio.h>

void DoNothingWithMemory(float* const copyByValue )
{
    float* copyByValueAgain = copyByValue ;
    /*
 *     As you see, the two var in this function, "copyByValueAgain" and "copyByValue", are copied by value. Therefore, even if the code block of inline asm below changes one of them, there's nothing to do with the var "p" in the main function. However, the fact is, the var "p" in the main function IS changed after executing the code block of inline asm below!
 *         */

    __asm__ __volatile__(
        "lea 8(%0),%0;" //In fact, nothing is done here. It's just a "lea", and has nothing to do with memory or pointer aliasing!
        :"+r"(copyByValueAgain)   // CHANGES HERE!!!!!!!!!!!
        ://"r"( copyByValueAgain ) // CHANGES HERE!!!!!!!!!!!
        :
        );
}

int main()
{
    float a; //just a place holder
    float* const p=&a; // As "p" is "const", it's impossible to change and should always point to "&a".
    for(int i = 0; i < 5; ++i) {
        printf("%p\n", p); // However, if you take a look at the output of this instruction, you will find that "p" changes every each loop, and that's really weird.
        DoNothingWithMemory(p);
    }
    return 0;
}
# g++ temp.cpp -O3 && ./a.out
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
# icc temp.cpp -O3 && ./a.out
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
#

Thanks,

Shenghong

0 Kudos
mengke_e_
Beginner
780 Views

shenghong-geng (Intel) wrote:

OK, I am clear about the issue now, in your case, copyByValueAgain is used as both input and output variable, you need to describe that to compiler so that it will not generate unexpected code.

You may refer to below link to know how to declare a variable in inline asm as both input and output.

http://stackoverflow.com/questions/15993934/extended-inline-assembly-sam...

And the working code is as below:

# cat temp.cpp
#include <stdio.h>

void DoNothingWithMemory(float* const copyByValue )
{
    float* copyByValueAgain = copyByValue ;
    /*
 *     As you see, the two var in this function, "copyByValueAgain" and "copyByValue", are copied by value. Therefore, even if the code block of inline asm below changes one of them, there's nothing to do with the var "p" in the main function. However, the fact is, the var "p" in the main function IS changed after executing the code block of inline asm below!
 *         */

    __asm__ __volatile__(
        "lea 8(%0),%0;" //In fact, nothing is done here. It's just a "lea", and has nothing to do with memory or pointer aliasing!
        :"+r"(copyByValueAgain)   // CHANGES HERE!!!!!!!!!!!
        ://"r"( copyByValueAgain ) // CHANGES HERE!!!!!!!!!!!
        :
        );
}

int main()
{
    float a; //just a place holder
    float* const p=&a; // As "p" is "const", it's impossible to change and should always point to "&a".
    for(int i = 0; i < 5; ++i) {
        printf("%p\n", p); // However, if you take a look at the output of this instruction, you will find that "p" changes every each loop, and that's really weird.
        DoNothingWithMemory(p);
    }
    return 0;
}
# g++ temp.cpp -O3 && ./a.out
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
0x7fffb6337e50
# icc temp.cpp -O3 && ./a.out
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
0x7fff29fdad84
#

Thanks,

Shenghong

Hey Shenghong,

Thank you very much for your explicit explanation!

MengKe

0 Kudos
Reply