[LLVMdev] confusion w.r.t. scalar evolution and nuw

Sanjoy Das sanjoy at playingwithpointers.com
Wed Jan 14 20:05:52 PST 2015


I've been doing some digging in this area (scev, wrapping arithmetic),
learning as much as I can, and have reached a point where I'm fairly
confused about the semantics of nuw in scalar evolution expressions.
Consider the following program:

define void @foo(i32 %begin) {
 entry:
  br label %loop

 loop:
  %idx = phi i32 [ %begin, %entry ], [ %idx.dec, %loop ]
  %idx.dec = sub nuw i32 %idx, 1
  %exit.condition = icmp eq i32 %idx.dec, 0
  br i1 %exit.condition, label %loop.exit, label %loop

 loop.exit:
  ret void
}

As long as %begin is positive, %idx.dec is not poison and the function
has defined behavior.

When I run opt -analyze -scalar-evolution on the IR, I get

Printing analysis 'Scalar Evolution Analysis' for function 'foo':
Classifying expressions for: @foo
  %idx = phi i32 [ %begin, %entry ], [ %idx.dec, %loop ]
  -->  {%begin,+,-1}<nuw><%loop>                Exits: 1
  %idx.dec = sub nuw i32 %idx, 1
  -->  {(-1 + %begin),+,-1}<nuw><%loop>         Exits: 0
Determining loop execution counts for: @foo
Loop %loop: backedge-taken count is (-1 + %begin)
Loop %loop: max backedge-taken count is -1

SCEV has mapped `%idx.dec' to `{(-1 + %begin),+,-1}<nuw>'!  This means
SCEV thinks `%idx.dec' will be poison in the very first iteration if
%begin is ult 1.

As an example on how this could blow up, if %begin was constant
(or LLVM was got smarter about ranges someday and learned to handle
non-constant ranges) in ScalarEvolution::getUnsignedRange, the
following code could fire:

  if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
    // If there's no unsigned wrap, the value will never be less than its
    // initial value.
    if (AddRec->getNoWrapFlags(SCEV::FlagNUW))
      if (const SCEVConstant *C = dyn_cast<SCEVConstant>(AddRec->getStart()))
        if (!C->getValue()->isZero())
          ConservativeResult =
            ConservativeResult.intersectWith(
              ConstantRange(C->getValue()->getValue(), APInt(BitWidth, 0)));

and conclude that %idx.dec is always UGE %begin.  This is a real bug
waiting to happen.

As far as I can tell, in the presence of no-wrap flags, 'sub X Y' is
not the same as 'add X -Y', and subtractions can be expressed as
additions only if they don't have any no-wrap flags on them.  While
I have not thought about nsw in depth, but it is possible there are
similar issues with nsw as well.

Is my reasoning broken at some point?  What gives?

-- Sanjoy



More information about the llvm-dev mailing list