diff --git a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp @@ -215,6 +215,20 @@ : Builder.CreateSExt(I->getOperand(0), I->getType(), I->getName() + ".neg"); break; + case Instruction::Select: { + // If both arms of the select are constants, we don't need to recurse. + // Therefore, this transform is not limited by uses. + auto *Sel = cast(I); + Constant *TrueC, *FalseC; + if (match(Sel->getTrueValue(), m_ImmConstant(TrueC)) && + match(Sel->getFalseValue(), m_ImmConstant(FalseC))) { + Constant *NegTrueC = ConstantExpr::getNeg(TrueC); + Constant *NegFalseC = ConstantExpr::getNeg(FalseC); + return Builder.CreateSelect(Sel->getCondition(), NegTrueC, NegFalseC, + I->getName() + ".neg", /*MDFrom=*/I); + } + break; + } default: break; // Other instructions require recursive reasoning. } diff --git a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll --- a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll +++ b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll @@ -98,10 +98,10 @@ define i8 @select_of_constants_multi_use(i1 %b) { ; CHECK-LABEL: @select_of_constants_multi_use( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i8 42, i8 -2 +; CHECK-NEXT: [[S_NEG:%.*]] = select i1 [[B:%.*]], i8 -42, i8 2 +; CHECK-NEXT: [[S:%.*]] = select i1 [[B]], i8 42, i8 -2 ; CHECK-NEXT: call void @use8(i8 [[S]]) -; CHECK-NEXT: [[N:%.*]] = sub nsw i8 0, [[S]] -; CHECK-NEXT: ret i8 [[N]] +; CHECK-NEXT: ret i8 [[S_NEG]] ; %s = select i1 %b, i8 42, i8 -2 call void @use8(i8 %s) @@ -111,10 +111,7 @@ define i32 @PR52261(i1 %b) { ; CHECK-LABEL: @PR52261( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 2, i32 -2 -; CHECK-NEXT: [[N:%.*]] = sub nsw i32 0, [[S]] -; CHECK-NEXT: [[A:%.*]] = and i32 [[S]], [[N]] -; CHECK-NEXT: ret i32 [[A]] +; CHECK-NEXT: ret i32 2 ; %s = select i1 %b, i32 2, i32 -2 %n = sub nsw i32 0, %s