Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -2370,11 +2370,31 @@ } break; - case Instruction::Select: + case Instruction::Select: { + // If we have a clamp pattern, we know that the number of sign bits will be + // the minimum of the clamp min/max range. + const Value *LHS, *RHS, *LHS2, *RHS2; + const APInt *CLow, *CHigh; + SelectPatternFlavor SPF = matchSelectPattern(U, LHS, RHS).Flavor; + if ((SPF == SPF_SMAX || SPF == SPF_SMIN) && match(RHS, m_APInt(CLow))) { + SelectPatternFlavor SPF2 = matchSelectPattern(LHS, LHS2, RHS2).Flavor; + if (getInverseMinMaxFlavor(SPF) == SPF2 && match(RHS2, m_APInt(CHigh))) { + if (SPF == SPF_SMIN) + std::swap(CLow, CHigh); + + if (CLow->sle(*CHigh)) { + Tmp = ComputeNumSignBits(LHS2, Depth + 1, Q); + return std::max(Tmp, std::min(CLow->getNumSignBits(), + CHigh->getNumSignBits())); + } + } + } + Tmp = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q); if (Tmp == 1) break; Tmp2 = ComputeNumSignBits(U->getOperand(2), Depth + 1, Q); return std::min(Tmp, Tmp2); + } case Instruction::Add: // Add can have at most one carry bit. Thus we know that the output Index: test/Transforms/InstCombine/max_known_bits.ll =================================================================== --- test/Transforms/InstCombine/max_known_bits.ll +++ test/Transforms/InstCombine/max_known_bits.ll @@ -17,3 +17,81 @@ ret i16 %t6 } +; This contains a min/max pair to clamp a value to 12 bits. +; By analyzing the clamp pattern, we can tell the add doesn't have signed overflow. +define i16 @min_max_clamp(i16 %x) { +; CHECK-LABEL: @min_max_clamp( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i16 [[X:%.*]], -2048 +; CHECK-NEXT: [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 -2048 +; CHECK-NEXT: [[C:%.*]] = icmp slt i16 [[B]], 2047 +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 2047 +; CHECK-NEXT: [[E:%.*]] = add nsw i16 [[D]], 1 +; CHECK-NEXT: ret i16 [[E]] +; + %a = icmp sgt i16 %x, -2048 + %b = select i1 %a, i16 %x, i16 -2048 + %c = icmp slt i16 %b, 2047 + %d = select i1 %c, i16 %b, i16 2047 + %e = add i16 %d, 1 + ret i16 %e +} + +; Same as above with min/max reversed. +define i16 @min_max_clamp_2(i16 %x) { +; CHECK-LABEL: @min_max_clamp_2( +; CHECK-NEXT: [[A:%.*]] = icmp slt i16 [[X:%.*]], 2047 +; CHECK-NEXT: [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 2047 +; CHECK-NEXT: [[C:%.*]] = icmp sgt i16 [[B]], -2048 +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 -2048 +; CHECK-NEXT: [[E:%.*]] = add nsw i16 [[D]], 1 +; CHECK-NEXT: ret i16 [[E]] +; + %a = icmp slt i16 %x, 2047 + %b = select i1 %a, i16 %x, i16 2047 + %c = icmp sgt i16 %b, -2048 + %d = select i1 %c, i16 %b, i16 -2048 + %e = add i16 %d, 1 + ret i16 %e +} + +; This contains a min/max pair to clamp a value to 12 bits. +; By analyzing the clamp pattern, we can tell that the second add doesn't +; overflow the original type and can be moved before the extend. +define i32 @min_max_clamp_3(i16 %x) { +; CHECK-LABEL: @min_max_clamp_3( +; CHECK-NEXT: [[A:%.*]] = icmp sgt i16 [[X:%.*]], -2048 +; CHECK-NEXT: [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 -2048 +; CHECK-NEXT: [[C:%.*]] = icmp slt i16 [[B]], 2047 +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 2047 +; CHECK-NEXT: [[G:%.*]] = sext i16 [[D]] to i32 +; CHECK-NEXT: ret i32 [[G]] +; + %a = icmp sgt i16 %x, -2048 + %b = select i1 %a, i16 %x, i16 -2048 + %c = icmp slt i16 %b, 2047 + %d = select i1 %c, i16 %b, i16 2047 + %e = add i16 %d, 1 + %f = sext i16 %e to i32 + %g = add i32 %f, -1 + ret i32 %g +} + +; Same as above with min/max order reversed +define i32 @min_max_clamp_4(i16 %x) { +; CHECK-LABEL: @min_max_clamp_4( +; CHECK-NEXT: [[A:%.*]] = icmp slt i16 [[X:%.*]], 2047 +; CHECK-NEXT: [[B:%.*]] = select i1 [[A]], i16 [[X]], i16 2047 +; CHECK-NEXT: [[C:%.*]] = icmp sgt i16 [[B]], -2048 +; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i16 [[B]], i16 -2048 +; CHECK-NEXT: [[G:%.*]] = sext i16 [[D]] to i32 +; CHECK-NEXT: ret i32 [[G]] +; + %a = icmp slt i16 %x, 2047 + %b = select i1 %a, i16 %x, i16 2047 + %c = icmp sgt i16 %b, -2048 + %d = select i1 %c, i16 %b, i16 -2048 + %e = add i16 %d, 1 + %f = sext i16 %e to i32 + %g = add i32 %f, -1 + ret i32 %g +}