Problem with functions not inlining

Discussion of chess software programming and technical issues.

Moderator: Ras

Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Problem with functions not inlining

Post by Sven »

Could you show one exact example of how you use that operator& in your code?

My suspicion is that your problem may be related to the way how you have defined your operator(s).

Sven
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Problem with functions not inlining

Post by Gerd Isenberg »

Sven Schüle wrote:Could you show one exact example of how you use that operator& in your code?

My suspicion is that your problem may be related to the way how you have defined your operator(s).

Sven
I have that suspicion too. He has (from his first post starting this thread) binary ops as members but not friends and passing the intrinsic type as parameter (which might all be fine, but may disable inlining).

Code: Select all

class xmm128i
{
  private:
   __m128i m_data;
  ...
   // very simple operator ...

   xmm128i operator &( __m128i const &other )
   { return xmm128i( _mm_and_si128( m_data, other ) ); }

   // many more operators ...
} 
I would try binary friends with const & xmm128 as two parameters, all necessary constructors

Code: Select all

class xmm128i
{
  private:
   __m128i m_data;
  ...
  // all kind of constructors, specially from  __m128i
   xmm128i(m128i a) {m_data = a;}


   // very simple operator ...
   friend xmm128i operator&(xmm128i const &a, xmm128i const & b) {
       return xmm128i( _mm_and_si128( a.m_data, b.m_data ) ); 
   } 
Gerd
User avatar
Greg Strong
Posts: 388
Joined: Sun Dec 21, 2008 6:57 pm
Location: Washington, DC

Re: Problem with functions not inlining

Post by Greg Strong »

Ok, home from work for the weekend and going to do some testing :)

First, I'll make a small function that just tries one operations. Then I'll mess with making it a friend function and other small changes. I'll do my best to narrow it down.

Thanks, I really appreciate the help, guys. Hopefully my tests will either point me to the problem or at least give me an acceptable workaround and I won't have to pester you too much ... I'll let you know how it goes!
Rein Halbersma
Posts: 751
Joined: Tue May 22, 2007 11:13 am

Re: Problem with functions not inlining

Post by Rein Halbersma »

Gerd Isenberg wrote: I would try binary friends with const & xmm128 as two parameters, all necessary constructors

Code: Select all

class xmm128i
{
  private:
   __m128i m_data;
  ...
  // all kind of constructors, specially from  __m128i
   xmm128i(m128i a) {m_data = a;}


   // very simple operator ...
   friend xmm128i operator&(xmm128i const &a, xmm128i const & b) {
       return xmm128i( _mm_and_si128( a.m_data, b.m_data ) ); 
   } 
Gerd
You could also define a member function operator&= and an ordinary (non-friend) function operator& like this:

Code: Select all

xmm128i& xmm128i::operator&=(const xmm128i& other)
{
         _mm_and_si128(m_data, other.m_data);
        return *this;
}

xmm128i& operator&(const xmm128i& left, const xmm128i& right)
{
        return xmm128i(left) ^= right;
}
This should be almost guaranteed to be inlined without copy overhead because of the Return Value Optimization mechanism.
jwes
Posts: 778
Joined: Sat Jul 01, 2006 7:11 am

Re: Problem with functions not inlining

Post by jwes »

Perhaps this is your problem. http://www.talkchess.com/forum/viewtopi ... 47&t=30342
Check your command line to make sure the options you think are set are really set.
wgarvin
Posts: 838
Joined: Thu Jul 05, 2007 5:03 pm
Location: British Columbia, Canada

Re: Problem with functions not inlining

Post by wgarvin »

Gerd Isenberg wrote:
Sven Schüle wrote:Could you show one exact example of how you use that operator& in your code?

My suspicion is that your problem may be related to the way how you have defined your operator(s).

Sven
I have that suspicion too. He has (from his first post starting this thread) binary ops as members but not friends and passing the intrinsic type as parameter (which might all be fine, but may disable inlining).

Code: Select all

class xmm128i
{
  private:
   __m128i m_data;
  ...
   // very simple operator ...

   xmm128i operator &( __m128i const &other )
   { return xmm128i( _mm_and_si128( m_data, other ) ); }

   // many more operators ...
} 
I would try binary friends with const & xmm128 as two parameters, all necessary constructors

Code: Select all

class xmm128i
{
  private:
   __m128i m_data;
  ...
  // all kind of constructors, specially from  __m128i
   xmm128i(m128i a) {m_data = a;}


   // very simple operator ...
   friend xmm128i operator&(xmm128i const &a, xmm128i const & b) {
       return xmm128i( _mm_and_si128( a.m_data, b.m_data ) ); 
   } 
Gerd
This should work fine, we use similar stuff all the time for 4d float vectors with SSE2 (i.e. 16-byte-aligned Vector4 class which is a wrapper around a __m128). With Microsoft's compiler at least, "const Vector4& foo" is the right way to pass such things as parameters, and ends up getting fully inlined. The constructor from __m128 (i.e. wrap) and cast operator to __m128 (i.e. unwrap) get inlined and disappear. The member operators work fine and get properly inlined.


If you can post a sample of the generated code, maybe someone will have a guess what is wrong with it?

Edit: also, check the compiler settings to make sure that (1) the processor type it is compiling for is the one you expect (in particular, does it know that its allowed to use SSE2 instructions?) and (2) intrinsic functions are enabled. If intrinsics are off, I can imagine the compiler generating a function call to a library function _mm_and_si128.. bleah. (just a wild guess though)
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Problem with functions not inlining

Post by Gerd Isenberg »

Rein Halbersma wrote: You could also define a member function operator&= and an ordinary (non-friend) function operator& like this:

Code: Select all

xmm128i& xmm128i::operator&=(const xmm128i& other)
{
   _mm_and_si128(m_data, other.m_data);
   return *this;
}
Yes, combined assignment operators return a reference and *this, since the object is not "destroyed" after leaving the scope of the function.
Rein Halbersma wrote:

Code: Select all

xmm128i& operator&(const xmm128i& left, const xmm128i& right)
{
    return xmm128i(left) ^= right; // should be &=
}
This should be almost guaranteed to be inlined without copy overhead because of the Return Value Optimization mechanism.
Guess you mean a friend? Despite, is it correct to return a reference (or pointer) to a temporary "object", which is no longer valid outside the scope of the function? Which would be like this pointer one, which hardly looks correct to me:

Code: Select all

friend xmm128i * operator&(const xmm128i& left, const xmm128i& right)
{
   xmm128i a(left);
   a &= right;
   return &a;  // pointer to a 
}
Even if it somehow works with references and objects inside registers, I would prefer this prototype

Code: Select all

friend xmm128i operator&(const xmm128i& left, const xmm128i& right)
{
    xmm128i a(left);
    a &= right;
    return a;
}
or as mentioned

Code: Select all

friend xmm128i operator&(xmm128i const &a, xmm128i const & b) {
   return xmm128i( _mm_and_si128( a.m_data, b.m_data ) );
}
Somehow for pure binary and commutative operators I found friends more "logically", since a & b == b & a, operator& is not bonded to be member of either a or b dependent on the order of expression. I use an SSE2 wrapper extensively for kogge-stone and that like and found the generated assembly rather optimal.

Gerd
wgarvin
Posts: 838
Joined: Thu Jul 05, 2007 5:03 pm
Location: British Columbia, Canada

Re: Problem with functions not inlining

Post by wgarvin »

Gerd Isenberg wrote:
Rein Halbersma wrote:

Code: Select all

xmm128i& operator&(const xmm128i& left, const xmm128i& right)
{
    return xmm128i(left) ^= right; // should be &=
}
This should be almost guaranteed to be inlined without copy overhead because of the Return Value Optimization mechanism.
Guess you mean a friend? Despite, is it correct to return a reference (or pointer) to a temporary "object", which is no longer valid outside the scope of the function?
You're right, that code looks wrong. You can't safely return a reference to a local variable, and you certainly can't return a reference to an unnamed temporary! The temporary is only in scope long enough to evaluate this expression, and then it goes away:

Code: Select all

xmm128i(left) ^= right
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Problem with functions not inlining

Post by Sven »

Greg Strong wrote:Ok, home from work for the weekend and going to do some testing :)

First, I'll make a small function that just tries one operations. Then I'll mess with making it a friend function and other small changes. I'll do my best to narrow it down.

Thanks, I really appreciate the help, guys. Hopefully my tests will either point me to the problem or at least give me an acceptable workaround and I won't have to pester you too much ... I'll let you know how it goes!
There have been a couple of suggestions about how to change your code in order to get it right. It is fine to try these, of course, and it will most probably lead to a solution. However, my first goal in such cases is to understand *why* the original version does not work as expected, and this is also what I expect to be your original intention when starting this thread.

So I would kindly ask you again to post an exact example of your original code where you are using your operator&, or similar. Everything else remains a mixture of feelings, suspicions and theories, and will never help to avoid making the same error again in future due to lack of understanding what *exactly* was wrong.

Sven
Rein Halbersma
Posts: 751
Joined: Tue May 22, 2007 11:13 am

Re: Problem with functions not inlining

Post by Rein Halbersma »

Gerd Isenberg wrote:
Rein Halbersma wrote:

Code: Select all

xmm128i& operator&(const xmm128i& left, const xmm128i& right)
{
    return xmm128i(left) ^= right; // should be &=
}
This should be almost guaranteed to be inlined without copy overhead because of the Return Value Optimization mechanism.
Guess you mean a friend? Despite, is it correct to return a reference (or pointer) to a temporary "object", which is no longer valid outside the scope of the function? Which would be like this pointer one, which hardly looks correct to me:
Gerd
Sorry for the typo, I meant &= and not ^=. I did mean to have a non-friend operator& though. There is no reason to clutter the class interface by adding friend operators that directly manipulate data members. Stroustrup also define binary operators in terms of their compound assignment cousins in his TC++PL book.

Return by value would of course always work. But the return by reference should not give any problems (it does not in my code). Can you give an example where it does give a problem?