I found 12 (6 if we compress the DeMorganized forms) patterns for logic-of-compares with a min/max constant while looking at PR45510:

https://bugs.llvm.org/show_bug.cgi?id=45510

The variations on those forms multiply the test cases by 8 (unsigned/signed, swapped compare operands, commuted logic operands).

We had partial logic to deal with these for the unsigned min (zero) case, but missed everything else.

I drafted an alternate implementation that uses ConstantRange instead of predicate+constant matching. It's slightly less code, but it requires many more code comments to follow the implied logic, so I think it's not worth the effort. I don't expect there's any noticeable compile-time impact for either form.

Here's an abuse of Alive2 to show the 12 basic signed variants of the patterns in 1 function:

http://volta.cs.utah.edu:8080/z/5Vpiyg

declare void @use(i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1) define void @src(i8 %x, i8 %y) { %m1 = icmp eq i8 %x, 127 %c1 = icmp slt i8 %x, %y %r1 = and i1 %m1, %c1 ; (X == MAX) && (X < Y) --> false %m2 = icmp ne i8 %x, 127 %c2 = icmp sge i8 %x, %y %r2 = or i1 %m2, %c2 ; (X != MAX) || (X >= Y) --> true %m3 = icmp eq i8 %x, -128 %c3 = icmp sgt i8 %x, %y %r3 = and i1 %m3, %c3 ; (X == MIN) && (X > Y) --> false %m4 = icmp ne i8 %x, -128 %c4 = icmp sle i8 %x, %y %r4 = or i1 %m4, %c4 ; (X != MIN) || (X <= Y) --> true %m5 = icmp eq i8 %x, 127 %c5 = icmp sge i8 %x, %y %r5 = and i1 %m5, %c5 ; (X == MAX) && (X >= Y) --> X == MAX %m6 = icmp ne i8 %x, 127 %c6 = icmp slt i8 %x, %y %r6 = or i1 %m6, %c6 ; (X != MAX) || (X < Y) --> X != MAX %m7 = icmp eq i8 %x, -128 %c7 = icmp sle i8 %x, %y %r7 = and i1 %m7, %c7 ; (X == MIN) && (X <= Y) --> X == MIN %m8 = icmp ne i8 %x, -128 %c8 = icmp sgt i8 %x, %y %r8 = or i1 %m8, %c8 ; (X != MIN) || (X > Y) --> X != MIN %m9 = icmp ne i8 %x, 127 %c9 = icmp slt i8 %x, %y %r9 = and i1 %m9, %c9 ; (X != MAX) && (X < Y) --> X < Y %m10 = icmp eq i8 %x, 127 %c10 = icmp sge i8 %x, %y %r10 = or i1 %m10, %c10 ; (X == MAX) || (X >= Y) --> X >= Y %m11 = icmp ne i8 %x, -128 %c11 = icmp sgt i8 %x, %y %r11 = and i1 %m11, %c11 ; (X != MIN) && (X > Y) --> X > Y %m12 = icmp eq i8 %x, -128 %c12 = icmp sle i8 %x, %y %r12 = or i1 %m12, %c12 ; (X == MIN) || (X <= Y) --> X <= Y call void @use(i1 %r1, i1 %r2, i1 %r3, i1 %r4, i1 %r5, i1 %r6, i1 %r7, i1 %r8, i1 %r9, i1 %r10, i1 %r11, i1 %r12) ret void } define void @tgt(i8 %x, i8 %y) { %m5 = icmp eq i8 %x, 127 %m6 = icmp ne i8 %x, 127 %m7 = icmp eq i8 %x, -128 %m8 = icmp ne i8 %x, -128 %c9 = icmp slt i8 %x, %y %c10 = icmp sge i8 %x, %y %c11 = icmp sgt i8 %x, %y %c12 = icmp sle i8 %x, %y call void @use(i1 0, i1 1, i1 0, i1 1, i1 %m5, i1 %m6, i1 %m7, i1 %m8, i1 %c9, i1 %c10, i1 %c11, i1 %c12) ret void }