smin(x, 0):
(select (x < 0), x, 0) -> ((x >> (size_in_bits(x)-1))) & x
smax(x, 0):
(select (x > 0), x, 0) -> (~(x >> (size_in_bits(x)-1))) & x The comparison is testing for a positive value, we have to invert the sign bit mask, so only do that transform if the target has a bitwise 'and not' instruction (the invert is free).
The transform is performed only when CMP has a single user to avoid
increasing total instruction number.
https://alive2.llvm.org/ce/z/euUnNm
https://alive2.llvm.org/ce/z/37339J
What about the more general cases (select (x > 0), y, 0) & (select (x < 0), y, 0)?
Although I think that requires a freeze:
define i8 @src(i8 %x, i8 %y) { %0: %c = icmp sge i8 %x, 0 %r = select i1 %c, i8 %y, i8 0 ret i8 %r } => define i8 @tgt(i8 %x, i8 %y) { %0: %c = ashr i8 %x, 7 %m = xor i8 %c, 255 %f = freeze i8 %y %r = and i8 %m, %f ret i8 %r } Transformation seems to be correct!