[cfe-dev] Evaluate constant condition of if statement has no effect

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Fri Aug 25 10:44:25 PDT 2017


On 25 Aug 2017 10:27, "bluechristlove via cfe-dev" <cfe-dev at lists.llvm.org>
wrote:

This is not specific example. If we don’t fix it, user will feel strange
why LHS of if stmt condition could do constant folding but RHS couldn’t.


1 || x is a constant expression.
x || 1 is not.
This is a property of the underlying programming language -- || short
circuits. The user needs to understand that.

>From the source code view’s point, this is our compiler bug.

In the ExprConstant.cpp:

    case Job::BinOpKind: {
      ...
      if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
        Queue.pop_back();
        return;
      }
      ...
      job.Kind = Job::BinOpVisitedLHSKind;
      enqueue(Bop->getRHS());
      return;
    }

    case Job::BinOpVisitedLHSKind: {
      ...
      Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
      Queue.pop_back();
      return;
    }

If we can not evaluate LHS successfully, we will evaluate RHS (function
VisitBinOp). In the function VisitBinOp:

  if (E->isLogicalOp()) {
    bool lhsResult, rhsResult;
    bool LHSIsOK = HandleConversionToBool(LHSResult.Val, lhsResult);
    bool RHSIsOK = HandleConversionToBool(RHSResult.Val, rhsResult);
    if (LHSIsOK) {
      if (RHSIsOK) {
        if (E->getOpcode() == BO_LOr)
          return Success(lhsResult || rhsResult, E, Result);
        else
          return Success(lhsResult && rhsResult, E, Result);
      }
    } else {
      if (RHSIsOK) {
*        // We can't evaluate the LHS; however, sometimes the result*
*        // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.*
        if (rhsResult == (E->getOpcode() == BO_LOr)) {
          return Success(rhsResult, E, Result);
        }
      }
    }

We can see that our previous implementation has consider this condition of
RHS constant folding. But because of ignore the parameter
Expr::SE_AllowSideEffects in the function ConstantFoldsToSimpleInteger:

bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
                                                   llvm::APSInt &ResultInt,
                                                   bool AllowLabels) {
  // FIXME: Rename and handle conversion of other evaluatable things
  // to bool.
  llvm::APSInt Int;
  if (!Cond->EvaluateAsInt(Int, getContext(), *Expr::SE_AllowSideEffects)*)
-------> allow side effect
    return false;  // Not foldable, not integer or not fully evaluatable.

We will not make the RHS constant folding happened.

bool DataRecursiveIntBinOpEvaluator::
       VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
                         bool &SuppressRHSDiags) {
….

  if (E->isLogicalOp()) {
    bool LHSAsBool;
    E->getLHS()->dumpColor();
    if (!LHSResult.Failed && HandleConversionToBool(LHSResult.Val,
LHSAsBool)) {
      // We were able to evaluate the LHS, see if we can get away with not
      // evaluating the RHS: 0 && X -> 0, 1 || X -> 1
      if (LHSAsBool == (E->getOpcode() == BO_LOr)) {
        Success(LHSAsBool, E, LHSResult.Val);
        return false; // Ignore RHS
      }
    } else {
      LHSResult.Failed = true;

     // Since we weren't able to evaluate the left hand side, it
      // might have had side effects.
*      if (!Info.noteSideEffect()) { --------> HERE!!!*
        return false;
      }
The detail source code analysis could be find in the comment 2 of
https://bugs.llvm.org/show_bug.cgi?id=34229

So, I think we should fix it.


*发件人:* John McCall <rjmccall at apple.com>
*发送时间:* 2017-08-23 01:30:45
*收件人:*  Frozen <bluechristlove at 163.com>
*抄送:*  cfe-dev at lists.llvm.org
*主题:* Re: [cfe-dev] Evaluate constant condition of if statement has no
effect

On Aug 21, 2017, at 12:28 AM, Frozen via cfe-dev <cfe-dev at lists.llvm.org>
wrote:
Simple Example:

int main()
{
  int x;
  if (x || 1) {}
}

Clang can not evaluate this condition and will emit IR like this:

define signext i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  %x = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  %0 = load i32, i32* %x, align 4
  %tobool = icmp ne i32 %0, 0
  br i1 %tobool, label %if.then, label %lor.lhs.false

lor.lhs.false:                                    ; preds = %entry
  br i1 true, label %if.then, label %if.end

if.then:                                          ; preds = %lor.lhs.false,
%entry
  br label %if.end

if.end:                                           ; preds = %if.then,
%lor.lhs.false
  %1 = load i32, i32* %retval, align 4
  ret i32 %1
}

However, when we swap the position of LHS and RHS(i.e. if (1 || x), Clang
can recognize it:

define signext i32 @main() #0 {
entry:
  %x = alloca i32, align 4
  ret i32 0
}

I also find the root issue and propose one potential solution in comment 2
of this link: https://bugs.llvm.org/show_bug.cgi?id=34229

Any idea?


There will always be some example of something that we generate less
efficiently at -O0 than we could.  Why is this example specifically worth
optimizing?

John.


_______________________________________________
cfe-dev mailing list
cfe-dev at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170825/5662fa0a/attachment.html>


More information about the cfe-dev mailing list