Topic: forceinline": Shouldn't this function be substituted inline?


Author: scorp@btinternet.com (Dave Harris)
Date: 1999/10/28
Raw View
ndekker@NO_SPAM_PLEASEnki.nl (Niels Dekker) wrote:
> My point is: a compiler can't always optimize correctly, because it
> doesn't have runtime information. In my case it doesn't know that
> my GoToNext function will be called repetitively for a zillion
> times. That is why I have to force the compiler to inline the
> function! So there's the need for a forceinline keyword!

You mean, there's a need to make runtime profiling feedback available to
the compiler. This is commonly done in other languages (eg Java with its
"just in time" compiling), and I believe some compilers do it for C++, too
(for example the Vortex compiler). Forceinline isn't necessarily the best
long-term approach to the problem.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Darron Shaffer <darron.shaffer@beasys.com>
Date: 1999/10/30
Raw View
Niels Dekker <ndekker@NO_SPAM_PLEASEnki.nl> writes:

> dennis51@my-deja.com wrote:
> > How big is this function, anyway?
> > Can you post it for us to see?
>
> Thanks for your replies.
> My point is: a compiler can't always optimize correctly, because it doesn't
> have runtime information. In my case it doesn't know that my GoToNext
> function will be called repetitively for a zillion times. That is why I have
> to force the compiler to inline the function! So there's the need for a
> forceinline keyword!
> On the other hand, I'm surprised that MSVC++ doesn't do inline-substition
> when I use the Standard C++ "inline". Because I think the GoToNext function
> is rather small.
>
> I must add, MSVC++ only refuses to expand the GoToNext in some cases.
> Here follows such a case. When I compile it in release mode (all warnings
> enabled), I get this warning:
> function 'bool __thiscall TCTraverser<3>::GoToNext(void)' not inlined
>
> ///////////////////////////////////////////////////////////////////////////
> #include <iostream>
> typedef unsigned int  UINT;
>
> template<UINT uNumberOfDims> class TCTraverser
> {
>   UINT m_auCoordinates[uNumberOfDims];
>   UINT m_auMaxCoordinates[uNumberOfDims];
>   UINT m_uIndex;
>   UINT m_uMaxIndex;
>   bool GoFromEndOfRowToNext(void); // Implemented out of line, below.
> public:
>   // MSVC++ 6.0 refuses to expand GoToNext, unless I replace "inline"
>   // with the Microsoft keyword "__forceinline".
>   inline bool GoToNext(void)
>   {
>     if( m_auCoordinates[0] < m_auMaxCoordinates[0] )
>     {
>       ++m_auCoordinates[0];
>       ++m_uIndex;
>       return true;
>     }
>     else
>     {
>       // Note: GoFromEndOfRowToNext is _not_ inline. So this function call
>       // doesn't make GoToNext much bigger.
>       return GoFromEndOfRowToNext();
>     }
>   }
>

As a practicle matter, you might try something like:


  inline bool GoToNext(void)
  {
    return (m_auCoordinates[0] >= m_auMaxCoordinates[0])
        ? GoFromEndOfRowToNext()
        : ++m_auCoordinates[0], ++m_uIndex, true;
  }

This will have only one exit from the inline function, which may help.

Regarding your larger question, C++ DOES have a "force-inline" --
macros.

However, macros are not a good fit in your case or many others,
because of scoping issues.

I feel that some form of forced inlining that fits within the scoping
system would fit within the "don't pay for it unless you ask for it"
model.  This would be like non-virtual member functions (considered an
optimization to be done by the compiler by Eiffel).

What the syntax should be is another question.  Perhaps the new inline
pragma syntax introduced by C99 combined with a standard pragma would
be a clean way to add this without introducing a new reserved word.

Another issue is limits -- can I write a 500 line function and demand
that it be inlined?

I think this should be seriously considered in about 5 years when the
standard is open for update.

Darron


--
               @  @             Darron J Shaffer
           @         @          Sr. Software Engineer
        @             @         darron.shaffer@beasys.com
      @   #           @         Voice: (972) 943-5137
    @     #          @          Fax:   (972) 943-5111
   @      #         o
  @       ####   @@@  ####      BEA Systems Inc.
  @       #   # @   @     #     The E-Commerce Transactions Company
  @       #   # @@@@@  ####     4965 Preston Park Blvd, Ste 500
   @      #   # @     #   #     Plano, TX 75093
     @ @  ####   @@@   ####     http://www.beasys.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Niels Dekker <ndekker@NO_SPAM_PLEASEnki.nl>
Date: 1999/10/27
Raw View
dennis51@my-deja.com wrote:
> How big is this function, anyway?
> Can you post it for us to see?

Thanks for your replies.
My point is: a compiler can't always optimize correctly, because it doesn't
have runtime information. In my case it doesn't know that my GoToNext
function will be called repetitively for a zillion times. That is why I have
to force the compiler to inline the function! So there's the need for a
forceinline keyword!
On the other hand, I'm surprised that MSVC++ doesn't do inline-substition
when I use the Standard C++ "inline". Because I think the GoToNext function
is rather small.

I must add, MSVC++ only refuses to expand the GoToNext in some cases.
Here follows such a case. When I compile it in release mode (all warnings
enabled), I get this warning:
function 'bool __thiscall TCTraverser<3>::GoToNext(void)' not inlined

///////////////////////////////////////////////////////////////////////////
#include <iostream>
typedef unsigned int  UINT;

template<UINT uNumberOfDims> class TCTraverser
{
  UINT m_auCoordinates[uNumberOfDims];
  UINT m_auMaxCoordinates[uNumberOfDims];
  UINT m_uIndex;
  UINT m_uMaxIndex;
  bool GoFromEndOfRowToNext(void); // Implemented out of line, below.
public:
  // MSVC++ 6.0 refuses to expand GoToNext, unless I replace "inline"
  // with the Microsoft keyword "__forceinline".
  inline bool GoToNext(void)
  {
    if( m_auCoordinates[0] < m_auMaxCoordinates[0] )
    {
      ++m_auCoordinates[0];
      ++m_uIndex;
      return true;
    }
    else
    {
      // Note: GoFromEndOfRowToNext is _not_ inline. So this function call
      // doesn't make GoToNext much bigger.
      return GoFromEndOfRowToNext();
    }
  }

  const UINT* GetCoordinates(void) const
  {
    return m_auCoordinates;
  }

  UINT GetIndex(void) const
  {
    return m_uIndex;
  }
  TCTraverser(const UINT puDims[]) { /* TODO: initialize all data! */ }
};


template<UINT uNumberOfDims>
bool TCTraverser<uNumberOfDims>::GoFromEndOfRowToNext(void)
{
  if( m_uIndex < m_uMaxIndex )
  {
    UINT uAxis = 1;

    m_auCoordinates[0] = 0;

    while( m_auCoordinates[uAxis] >= m_auMaxCoordinates[uAxis] )
    {
      m_auCoordinates[uAxis] = 0;
      ++uAxis;
    }
    ++m_auCoordinates[uAxis];

    ++m_uIndex;
    return true;
  }
  else
  {
    return false;
  }
}


template<class FUNCTOR_CLASS>
void MyIterate(FUNCTOR_CLASS Functor, const UINT puDims[3])
{
  TCTraverser<3> Traverser(puDims);
  do
  {
    Functor(Traverser.GetIndex(), Traverser.GetCoordinates(), puDims);

  } while( Traverser.GoToNext() );
}


template<class TYPE> class TCMyFunctor
{
  const TYPE* const m_pData;
public:
  TCMyFunctor(const TYPE* const pData): m_pData(pData) {}
  void operator()(
    const UINT uIndex, const UINT puCoordinates[3], const UINT puDims[3])
  {
    std::cout << m_pData[uIndex]
      << puCoordinates[0] << puDims[0]
      << puCoordinates[1] << puDims[1]
      << puCoordinates[2] << puDims[2];
  }
};


// Test program.
void Test(char* pc, int* pi, double* pd)
{
  UINT auDims[3] = {512, 512, 512};

  MyIterate(TCMyFunctor<char>(pc), auDims);
  MyIterate(TCMyFunctor<int>(pi), auDims);
  MyIterate(TCMyFunctor<double>(pd), auDims);
}
///////////////////////////////////////////////////////////////////////////

See also the replies that I got from news:microsoft.public.vc.language

Regards
  Niels Dekker
  ndekker at nki.nl
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]