1

Here's a simple code

void GlobalAlterA(A *a) { a->m = 1; }
struct A { int n, int m; };
struct Z: public A { void AlterA() { GlobalAlterA(this); } };
struct Y: public Z {};
struct X: public Y 
{
    int AsValue()
    {
       switch (n)
       {
           case 0: return m;
           default: AlterA(); return m;
       }
    }
};

Now, the problem with this code is that gcc optimizer throws away all AsValue() code except "return m", because, I suppose, it does not see the GlobalAlterA() body and doesn't know that AlterA() can change the "m" member.

Is there a way to fix this except switching off optimization for specific parts of code? E.g. tricks like volatile specifiers, etc.

queen3
  • 15,333
  • 8
  • 64
  • 119
  • What version of gcc are you using? After modifying your code so that it compiles, it produces the values I'd expect (both with "no explicit optimisation" and `-O3`). Maybe you could actually show us how you are using the above code. – Mats Petersson Apr 23 '13 at 14:19
  • 2
    Could you post a complete demonstration of the problem? The compiler certainly shouldn't remove the call to `AlterA` if it affects the program's behaviour. – Mike Seymour Apr 23 '13 at 14:19
  • 3
    I've just compiled this with -O3 using gcc 4.7.2 to assembly language and looked it it on x86_64 and it doesn't appear to do what you say. I added code "std::cin >> x.n >> x.m" at the start to set the values of n and m and fixed a couple of compile things such as using type A before it's defined and couldn't reproduce this at all. – jcoder Apr 23 '13 at 14:20
  • Do you initialize `n` and `m` somewhere? Otherwise `switch(n)` is undefined. – Bo Persson Apr 23 '13 at 14:21
  • No, it's not easy to reproduce in a small example, code is spread across shared libraries, e.g. GlobalAlterA() is in a separate one. – queen3 Apr 23 '13 at 14:33
  • Are there any const and mutable applied to the members of struct A? – Adder Apr 23 '13 at 14:49
  • No, but it's in fact a complex nested struct/union stuff. – queen3 Apr 23 '13 at 14:53

1 Answers1

2

This is already assumed by the optimizer, so you cannot tell it to assume things it already assumes.

However, if you think you're changing the value, but in fact are hitting Undefined Behavior (e.g. because you modify m through a type-punned pointer, or union abuse), then the optimizer is well within its rights to assume m didn't change. The best fix is of course to remove that UB, or (failing that) at least hide it from the optimizer.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Does optimizer know and assume what GlobalAlterA does (with or without UB) when GlobalAlterA is inside a separate shared library? – queen3 Apr 23 '13 at 15:23
  • 2
    @queen3: It MUST assume that `GlobalAlterA` changes all variable that can be changed without UB, and it MAY assume that it changes only those. Shorter: the optimizer may assume no UB. Well-known example: Given `int i`, `i+1 > 1` may be assumed true. Overflow is UB, so `INT_MAX + 1 > INT_MAX == true` is a valid optimization. – MSalters Apr 23 '13 at 15:29
  • Trying to trick the compiler into behaving in a particular way in the face of UB will burn you again and again. You may trick this version of the compiler in this case to "do what you want," but every time you upgrade the compiler, or change any of the code that uses it, it will bite you again in another subtle bug. You have to convert the UB into defined behavior. Your "complex nested struct/union stuff" almost certainly needs to be de-complexified. – Rob Napier Apr 23 '13 at 15:44
  • Useful discussion of a common union abuse and how it leads to UB: http://stackoverflow.com/questions/10271929/union-for-uint32-t-and-uint8-t4-undefined-behavior – Rob Napier Apr 23 '13 at 15:48