Hi -
The answer to this question may help to resolve larger questions about intrinsics and vectorization that were discussed at the dev mtg last week, but let’s start with the basics:
Which, if any, of these is the canonical IR?
; ret = x < y ? 0 : x-y
define i32 @max1(i32 %x, i32 %y) {
%sub = sub nsw i32 %x, %y
%cmp = icmp slt i32 %x, %y ; cmp is independent of sub
%sel = select i1 %cmp, i32 0, i32 %sub
ret i32 %sel
}
; ret = (x-y) < 0 ? 0 : x-y
define i32 @max2(i32 %x, i32 %y) {
%sub = sub nsw i32 %x, %y
%cmp = icmp slt i32 %sub, 0 ; cmp depends on sub, but this looks more like a max?
%sel = select i1 %cmp, i32 0, i32 %sub
ret i32 %sel
}
; ret = (x-y) > 0 ? x-y : 0
define i32 @max3(i32 %x, i32 %y) {
%sub = sub nsw i32 %x, %y
%cmp = icmp sgt i32 %sub, 0 ; canonicalize cmp+sel - looks even more like a max?
%sel = select i1 %cmp, i32 %sub, i32 0
ret i32 %sel
}
define i32 @max4(i32 %x, i32 %y) {
%sub = sub nsw i32 %x, %y
%max = llvm.smax.i32(i32 %sub, i32 0) ; this intrinsic doesn’t exist today
ret i32 %max
}
FWIW, InstCombine doesn’t canonicalize any of the first 3 options currently. Codegen suffers because of that (depending on the target machine and data types). Regardless of the IR choice, some backend fixes are needed.
Another possible consideration is the structure/accuracy of the cost models used by the vectorizers and other passes. I don’t think they ever special-case the cmp+sel pair as a possibly unified (and therefore cheaper than the sum of the parts) operation.
Note that we added FP variants for min/max ops with:
https://reviews.llvm.org/rL220341