views:

235

answers:

7

The following testing code does correctly in VS either with debug or release, so does it in gcc. It also does correctly for ICC with debug, but not when optimization enabled (-O2).


#include <cstdio>

class tClassA{
public:
  int m_first, m_last;

  bool isEmpty() const {return (m_first == m_last);}
  void updateFirst() {m_first = m_first + 1;}
  void updateLast() {m_last = m_last + 1;}

  tClassA() : m_first(0), m_last(0) {}

  ~tClassA() {}

  void doSomething() {printf("should not reach here\r\n");}

};


int main() {

 tClassA q;

 while(true) {

    while(q.isEmpty()) ;

    q.doSomething();
  }

  return 1;

}

It is supposed to stoped at while(q.isEmpty()). When -O2 enabled under ICC (release), however, it starts to "doSomething" infintely.

Since this is single-threaded program AND isEmpty() should be evaluated as "true", I can find no reason the ICC should behave in this way? Do I miss anything?

+1  A: 

Your best bet is to take the resulting binary step into it and dis-assemble the main function and see what assembly was generated. Not saying you will be able to see a bug, but you can see if something was optimized out.

linuxuser27
You can't. The asm code is optimized away everything and you can see nothing.
Samuel
I am not sure what that means. Are you saying that you dis-assembled the resulting binary and the while() loop was gone?
linuxuser27
+3  A: 

It sure sounds like a bug. Here's a (pretty wild) guess about what reasoning might have lead to it...

After inlining, it sees:

while (q.m_first == q.m_last) /* do nothing */ ;
do_something();

and any sequence of do nothing repeatedly ; do something can be translated to simply "do something". This falls down if the repeated part is endless (as in this case). But perhaps they don't test their compiling on examples that intentionally have endless looping ;-).

Edmund
A: 

I think it may have been your version of gcc. I compiled your prog under 4.4.2 and it worked exactly as it should have.

BT
This is icc, not gcc
Merlyn Morgan-Graham
+2  A: 

Any chance the actual code that you built and ran was missing the semicolon after while(q.isEmpty()) ? That would certainly result in the next line being called infinitely.

TheUndeadFish
+1 for reminding me of something similar
Chubsdad
1. there is semicolon2. the same result with while(q.isEmpty()) {}, or while(q.isEmpty()) {true;}
Samuel
To whoever: Was a down-vote really necessary? I've seen a number of cases on SO where the posted code was not the exact code being used and where actual problem had been left out or fixed in the translation. I just wanted to help make sure this wasn't the result of a simple but easy to overlook mistake. (After all, haven't we all occasionally wasted time on a bug due to something like a mistaken semicolon?)
TheUndeadFish
+9  A: 

Because the while (q.isEmpty()) ; loop contains no statements that can ever cause an externally-visible side-effect, the entire loop is being optimised out of existence. It's the same reason that:

for (int i = 0; i < 10; i++)
    ;

could be optimised out of existence, as long as i was not volatile (stores to volatile objects are part of the "externally visible" effects of a program).

In the C language, it is actually an outstanding bone of contention as to whether an infinite loop is allowed to be optimised away in this manner (I do not know what the situation is with C++). As far as I know, a consensus has never been reached on this issue - smart and knowledgeable people have taken both sides.

caf
This could be the reason.The following code works correctly:static int A=0; while(q.isEmpty()) {A = A+ 1;}But not the following:static int A=1; while(q.isEmpty()) {A;}
Samuel
Interesting. An infinite loop doing nothing - nice optimization opportunity (and it is understandable why someone may disagree).
Suma
One more thing: if while(true) is used for while(q.isEmpty()), the code works correctly.
Samuel
+2  A: 

As a slight aside, this version of icc does what you want. That is, it never calls doSomething().

[9:41am][wlynch@computer /tmp] icc --version
icc (ICC) 11.0 20081105
sharth
+2  A: 

The C++ standard allows loops without side-effects to be removed, even if they don't terminate:

It is generally felt that it is important to allow the transformation of potentially non-terminating loops (e.g. by merging two loops that iterate over the same potentially infinite set, or by eliminating a side-effect-free loop), even when that may not otherwise be justified in the case in which the first loop never terminates. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm

See the discussion here: http://blog.regehr.org/archives/161

Charles