Open
Description
Rust in which we spotted this originally: https://godbolt.org/z/8xM3P9xP5
Take this IR:
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
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):
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
}