[PATCH] D48853: [SCEV] Add [zs]ext{C, +, x} -> (D + [zs]ext{C-D, +, x})<nuw><nsw> transform

Roman Tereshin via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 19 15:48:33 PDT 2018


rtereshin added inline comments.


================
Comment at: lib/Analysis/ScalarEvolution.cpp:1566-1568
+static APInt extractConstantWithoutWrapping(ScalarEvolution &SE,
+                                            const SCEVConstant *ConstantTerm,
+                                            const SCEVAddExpr *FullExpr) {
----------------
mzolotukhin wrote:
> Could you please also add a description for `FullExpr`? It might be helpful to add even more examples here and describe the intended use (e.g. `ConstantTerm` is `Start` and `FullExpr` is `Step` of an `AddRec` expression).
Thanks for looking into this!

> Could you please also add a description for FullExpr?
Sure, will do.

> It might be helpful to add even more examples here and describe the intended use (e.g. ConstantTerm is Start and FullExpr is Step of an AddRec expression).
The next overload is the one that handles AddRec with parameter names being `ConstantStart` and `Step`. Do you think the names are self-explanatory or I need to elaborate in a comment?

As for AddExpr-version here I'm going to elaborate what `FullExpr` is and hopefully that will be clear enough.


================
Comment at: lib/Analysis/ScalarEvolution.cpp:1585-1588
+  for (unsigned I = 1, E = FullExpr->getNumOperands(); I < E && TZ; ++I)
+    TZ = std::min(TZ, SE.GetMinTrailingZeros(FullExpr->getOperand(I)));
+  if (TZ)
+    return TZ < BitWidth ? C.trunc(TZ).zext(BitWidth) : C;
----------------
mzolotukhin wrote:
> Just checking my understanding: we're basically finding the largest common denominator here, which is also a power of 2, right?
> we're basically finding the largest common denominator here, which is also a power of 2, right?
This
```
  uint32_t TZ = BitWidth;
  for (unsigned I = 1, E = FullExpr->getNumOperands(); I < E && TZ; ++I)
    TZ = std::min(TZ, SE.GetMinTrailingZeros(FullExpr->getOperand(I)))
```
piece effectively does exactly that, yes. Another way to look at it is to say that we have an `AddExpr` that looks like `(C + x + y + ...)`, where `C` is a constant and x, y, ... are arbitrary SCEVs, and we're computing the minimum number of trailing zeroes guaranteed of the sum w/o the constant term: `(x + y + ...)`. If, for example, those terms look like follows:
```
        i
XXXX...X000
YYYY...YY00
    ...
ZZZZ...0000
```
then the rightmost non-guaranteed zero bit (a potential one at i-th position above) can change the bits of the sum to the left, but it can not possibly change the bits to the right. So we can compute the number of trailing zeroes by taking a minimum between the numbers of trailing zeroes of the terms.

Now let's say that our original sum with the constant is effectively just `C + X`, where `X = x + y + ...`. Let's say we've got 2 guaranteed trailing zeros for `X`:
```
         j
CCCC...CCCC
XXXX...XX00
```
Any bit of `C` to the left of `j` may in the end cause the `C + X` sum to wrap, but the rightmost 2 bits of `C` (at positions `j` and `j - 1`) do not affect wrapping in any way. If the upper bits cause a wrap, it will be a wrap regardless of the values of the 2 least significant bits of `C`. If the upper bits do not cause a wrap, it won't be a wrap regardless of the values of the 2 bits on the right (again).

So let's split C to 2 constants like follows:
```
0000...00CC  = D
CCCC...CC00  = (C - D)
```
and the whole sum like `D + (C - D + X)`. The second term of this new sum looks like this:
```
CCCC...CC00
XXXX...XX00
-----------
YYYY...YY00
```
The sum above (let's call it `Y`)) may or may not wrap, we don't know, so we need to keep it under a sext/zext. Adding `D` to that sum though will never wrap, signed or unsigned, if performed on the original bit width or the extended one, because all that that final add does is setting the 2 least significant bits of `Y` to the bits of `D`:
```
YYYY...YY00 = Y
0000...00CC = D
----------- <nuw><nsw>
YYYY...YYCC
```
Which means we can safely move that D out of the sext or zext and claim that the top-level sum neither sign wraps nor unsigned wraps.

Let's run an example, let's say we're working in `i8`s and the original expression (zext's or sext's operand) is `21 + 12x + 8y`. So it goes like this:
```
0001 0101  // 21
XXXX XX00  // 12x
YYYY Y000  // 8y

0001 0101  // 21
ZZZZ ZZ00  // 12x + 8y  // true, alternatively one can say that gcd(12, 8) is guaranteed to have 2 zeroes on the right

0000 0001  // D
0001 0100  // 21 - D = 20
ZZZZ ZZ00  // 12x + 8y

0000 0001  // D
WWWW WW00  // 21 - D + 12x + 8y = 20 + 12x + 8y
```
therefore `zext(21 + 12x + 8y)` = `(1 + zext(20 + 12x + 8y)<nuw><nsw>`


Repository:
  rL LLVM

https://reviews.llvm.org/D48853





More information about the llvm-commits mailing list