1

I've been watching Mike Acton's talk on Data-oriented design in C++ in CppCon 2014, and he gives this example:

int Foo::Bar(int count)
{
    int value = 0;
    for (int i = 0; i < count; i++) {
        if (m_someDataMemberOfFoo) value++
    }
    return value;
}

And explains how some compilers keep re-reading m_someDataMemberOfFoo in every iteration, perhaps because its value might change due to concurrent access. Regardless of whether it's appropriate for the compiler to do so - can one tell the compiler to specifically ignore any possibility of concurrent access to anything during the execution of some method, so that it may optimize better?

In other words, can I tell it the compiler that this is __restrict__ed?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 4
    Any compiler worthy of the name would consider hoisting the check out of the loop, or at least saving `m_someDataMemberOfFoo` in a register. Any program that attempts to modify `m_someDataMemberOfFoo` concurrently with this code exhibits undefined behavior. – Igor Tandetnik Apr 26 '15 at 21:51
  • @IgorTandetnik: Not necessarily. That's making an unjustified semantic assumption. Maybe `m_someDataMemberOfFoo` is supposed to change by concurrent modification? – einpoklum Jul 17 '15 at 13:12
  • I feel the assumption is justified in context. If `m_someDataMemberOfFoo` is thread-safe (say, an `atomic`), and it's expected that it would be concurrently modified, then the whole issue is moot. It would not be the case that "*some* compilers keep re-reading `m_someDataMemberOfFoo` in every iteration" - all compilers would be doing that, and it would be perfectly valid and reasonable - indeed, required - for them to do so. – Igor Tandetnik Jul 17 '15 at 16:37

2 Answers2

4
  1. __restrict__ is not standardized in C++, so this question can only be answered on a particular platform. For GCC, you can apply __restrict__ to this in the same way as const:

    void T::fn () __restrict__
    
  2. There is no potential aliasing in your example. C++ specifies undefined behavior for data races.

  3. A new system for C++ restricted pointers is being developed. It will likely be standardized in C++17. Support for this is one of the stated design goals.

Community
  • 1
  • 1
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Aliasing is not what I'm worried about, it's concurrent access. Suppose my loop was while `(! m_YouRangSir) { mySleep(Miliseconds(1000)); }` ... – einpoklum Apr 27 '15 at 09:58
  • Also, - the proposal seems very verbose and awkward to use, I wish they do something simple like `__restrict__` with extra verbiage for ambiguities. – einpoklum Apr 27 '15 at 10:09
  • @einpoklum In this context, aliasing includes concurrent access. If there were a critical section in the loop, it would have to re-read the member. If you want the `restrict` keyword, you can do `#define restrict [[alias_set()]]`. Attributes can be placed at the start of the declaration or just before the declarator-id. I'm not sure how the proposal can apply to `this`, now that I look at it; the examples only show *allowing* aliasing with `this`. – Potatoswatter Apr 27 '15 at 10:41
2

With the code that you posted, code compiled with any optimisation at all should not re-read that class member. However, take this similar code:

void Foo::Bar(int count, int* result)
{
    *result = 0;
    for (int i = 0; i < count; i++) {
        if (m_someDataMemberOfFoo) (*result)++;
    }
}

In this case, the compiler must assume that result == &m_someDataMemberOfFoo is a possibility, if that member has type int. Obviously any developer calling it the way deserves to get his programming license revoked, but it is legal and the compiler must handle this correctly.

This is even the case if you mark the method as "const". A const method is not allowed to modify any part of *this by using the this pointer (with some exceptions). However, members of *this can be legally modified in other ways if the actual object is not const.

"restrict" in C is intended to fix the problem, and hopefully the same feature in C++ would fix it in this case.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • Couldnt the compiler - at least in theory - still optimize the example code you presented, because even if it assumes result==&m_someDataMemberOfFoo, that value is set to 0 and the increment is never reached. If the increment is reached, result cannot alias m_someDataMemberOfFoo. (That doesnt in any way invalidate the point you are making, just asking) – Philipp Lenk Apr 26 '15 at 22:52
  • In the talk I linked to, MSVC does compile the code with m_someDataMemberOfFoo in the loop condition to re-read the member repeatedly... – einpoklum Apr 27 '15 at 09:59