This adds a instcombine match for code that attempts to perform signed saturating arithmetic by casting to a higher type. For example:
https://godbolt.org/z/9knBnP
As can be seen the unsigned cases are already matched, but signed are not. Adding them for these cases involves matching the min(max(add a b)) nodes, with proper truncs and extends.
There is some work in D68643 to make the default lowering for these better. With that I believe that the intrinsic is a better choice than extending into a larger type (although it's obviously hard to tell for all architectures). This also helps with vectorization, especially in dsp routines that often want to use saturating arithmetic.
This also adds a m_SpecificAPInt matcher which seemed to be useful, similar to m_SpecificInt but taking an APInt for cases like this where using an APInt make sense.
%a_wide = sext i4 %a to i8 %b_wide = sext i4 %b to i8 %add = add i8 %b_wide, %a_wide %should_not_clamp_high = icmp slt i8 %add, 7 %clamped_high = select i1 %should_not_clamp_high, i8 %add, i8 7 %should_not_clamp_low = icmp sgt i8 %clamped_high, -8 %clamped_low = select i1 %should_not_clamp_low, i8 %clamped_high, i8 -8 %res = trunc i8 %clamped_low to i4 ret i4 %res => %res = sadd_sat i4 %a, %b ret i4 %res %b_wide = sext i4 %b to i8 %a_wide = sext i4 %a to i8 %add = add i8 %b_wide, %a_wide %should_not_clamp_high = icmp slt i8 %add, 7 %clamped_high = select i1 %should_not_clamp_high, i8 %add, i8 7 %should_not_clamp_low = icmp sgt i8 %clamped_high, -8 %clamped_low = select i1 %should_not_clamp_low, i8 %clamped_high, i8 -8 Done: 1 Optimization is correct!