Почему этот код ведет себя по-другому, если используется оптимизация (-O2, -O3)?

Мне пришлось закодировать некоторые процедуры проверки, и они, похоже, ведут себя по-другому, если вы используете -O0, -O1, -O2 или -O3.

Ниже я создал минимальный пример, который отлично подходит для -O0 и -O1. Но с использованием -O2 или -O3 поведение изменилось. В случае -O0 и -O1 for-loop увеличивает значение целого числа, и первый раз, когда он достигает максимума, происходит переполнение и запускается процедура проверки. В другом случае for-loop никогда не прерывается, хотя целое число становится отрицательным.

Код

#include <iostream>

inline bool check(const int i) {
  if (i < 0)
    return false;
  else
    return true;
}

int main() {
  for (int i = 0;; i += 50000000) {
    std::cout << i << std::endl;
    const bool succ = check(i);
    if (succ == false) {
      std::cout << "Overflow: " << i << std::endl;
      break;
    }
  }
  return 0;
}

Почему компилятор разрешил оптимизировать это?

Пытаясь использовать gcc, clang и icc, только icc делает это правильно во всех вариантах оптимизации, другие два не сделали.