https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72785

--- Comment #6 from Jeffrey A. Law <law at redhat dot com> ---
So this is a very interesting little issue that highlights a deficiency in the 
semantics of __builtin_constant_p.

So prior to threading we have:

;;   basic block 4, loop depth 0, count 0, freq 10000, maybe hot
;;    prev block 3, next block 5, flags: (NEW, REACHABLE, VISITED)
;;    pred:       2 [50.0%]  (TRUE_VALUE,EXECUTABLE)
;;                3 [100.0%]  (FALLTHRU,EXECUTABLE)
  # iftmp.0_2 = PHI <a.1_5(2), 1(3)>
  b = iftmp.0_2;
  _1 = __builtin_constant_p (iftmp.0_2);
  if (_1 != 0)
    goto <bb 5>;
  else
    goto <bb 7>;
;;    succ:       5 [54.0%]  (TRUE_VALUE,EXECUTABLE)
;;                7 [46.0%]  (FALSE_VALUE,EXECUTABLE)

;;   basic block 5, loop depth 0, count 0, freq 5400, maybe hot
;;    prev block 4, next block 6, flags: (NEW, REACHABLE, VISITED)
;;    pred:       4 [54.0%]  (TRUE_VALUE,EXECUTABLE)
  if (iftmp.0_2 != 0)
    goto <bb 6>;
  else
    goto <bb 7>;
;;    succ:       6 [36.6%]  (TRUE_VALUE,EXECUTABLE)
;;                7 [63.4%]  (FALSE_VALUE,EXECUTABLE)

;;   basic block 6, loop depth 0, count 0, freq 1979, maybe hot
;;    prev block 5, next block 7, flags: (NEW, REACHABLE, VISITED)
;;    pred:       5 [36.6%]  (TRUE_VALUE,EXECUTABLE)
  ____ilog2_NaN ();

That's all fine and good.  Threading wants to lookup the value of iftmp.0_2 in
an attempt to eliminate the conditional in BB5.  And it finds that the path
3->4->5 will result in iftmp.0_2 having the value 1.  So it isolates that path.

After isolation things look  like this:

;;   basic block 3, loop depth 0
;;    pred:       2
  # iftmp.0_8 = PHI <1(2)>
  b = iftmp.0_8;
  _10 = __builtin_constant_p (iftmp.0_8);
  if (_10 != 0)
    goto <bb 6>;
  else
    goto <bb 7>;
;;    succ:       6
;;                7

;;   basic block 4, loop depth 0
;;    pred:       2
  # iftmp.0_2 = PHI <a.1_5(2)>
  b = iftmp.0_2;
  _1 = __builtin_constant_p (iftmp.0_2);
  if (_1 != 0)
    goto <bb 5>;
  else
    goto <bb 7>;
;;    succ:       5
;;                7

;;   basic block 5, loop depth 0
;;    pred:       4
  if (iftmp.0_2 != 0)
    goto <bb 6>;
  else
    goto <bb 7>;
;;    succ:       6
;;                7

;;   basic block 6, loop depth 0
;;    pred:       5
;;                3
  ____ilog2_NaN ();
;;    succ:       7


Note how the path leading out of block 3 will never pass through the
conditional in block 5.  That's the primary effect of jump threading.


The most "obvious" interpretation is that "b" is not constant in this case at
the source level and thus __b_c_p must return zero.  But how does one deal with
cases where analysis such as VRP, CPROP, etc prove certain edges are not
executable and thus certain paths to a b_c_p call are eliminated and the
"obvious" non-constant b_c_p argument turns into a constant argument.  This
could happen virtually with any optimization that eliminates an edge in the
CFG.  Proving edge removal does not change the runtime result of a b_c_p call
is almost certainly akin to the halting problem.

Similarly such an interpretation would essentially mean that a block with a
b_c_p call can only be duplicated if we can prove that the original and
duplicate have the same runtime result as the original -- which we might be
able to prove in some cases, but the context necessary to do so is likely not
available in the places where we have to make that determination -- essentially
we'll likely have to disallow duplication of blocks with b_c_p.

I want folks to realize that the "obvious" interpretation may have very
significant secondary effects and may ultimately result in cases where we must
either totally cripple optimizers or declare that the "obvious" semantics
simply can't be supported.

Reply via email to