Issue 146087
Summary Missed optimization when known bits would permit transforming an `and` into subtruction
Labels new issue
Assignees
Reporter WaffleLapkin
    Rust in which we spotted this originally: https://godbolt.org/z/8xM3P9xP5

Take this IR:
```llvm
define noundef i8 @f(i8 noundef %0) unnamed_addr {
  ; check if two highest bits are set
  %2 = lshr i8 %0, 6
  %3 = icmp eq i8 %2, 3
  br i1 %3, label %4, label %7

4:                                                ; preds = %1
  ; if so, get the value of the lower 6 bits + 1
  %5 = and i8 %0, 63
  %6 = add i8 %5, 1
  br label %8

7:                                                ; preds = %1
  br label %8

8:                                                ; preds = %7, %4
  %9 = phi i8 [ %6, %4 ], [ -1, %7 ]
  ret i8 %9
}
```
Today `--passes=instcombine` turns it into

```llvm
define noundef i8 @f(i8 noundef %0) unnamed_addr {
  %2 = icmp ugt i8 %0, -65
  br i1 %2, label %3, label %6

3:
  %4 = and i8 %0, 63 ; 😢
  %5 = add nuw nsw i8 %4, 1
  br label %7

6:
  br label %7

7:
  %8 = phi i8 [ %5, %3 ], [ -1, %6 ]
  ret i8 %8
}
```

However the `and` and `add` could be combined too -- they are used in the branch where `%0 > -65` (two highest bits in `%0` are set), which means that `and i8 %0, 63` (`& 0b111111`) could be replaced with `add i8, %0, -192` (`- 0b11000000`) and then trivially folded with the other `add`. That is, the resulting IR should look like this (https://alive2.llvm.org/ce/z/Go8nxD):

```llvm
define noundef i8 @tgt(i8 noundef %0) unnamed_addr {
  %2 = icmp ugt i8 %0, -65
  br i1 %2, label %3, label %6

3:
  %5 = add nuw nsw i8 %0, -191 ; 🌸
  br label %7

6:
  br label %7

7:
  %8 = phi i8 [ %5, %3 ], [ -1, %6 ]
  ret i8 %8
}
```
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to