diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -2017,7 +2017,8 @@ } //===----------------------------------------------------------------------===// -// Matchers for overflow check patterns: e.g. (a + b) u< a +// Matchers for overflow check patterns: e.g. (a + b) u< a, (a ^ -1) @@ -2048,6 +2049,13 @@ if (AddExpr.match(ICmpRHS) && (ICmpLHS == AddLHS || ICmpLHS == AddRHS)) return L.match(AddLHS) && R.match(AddRHS) && S.match(ICmpRHS); + // (a ^ -1) getOperand(0); Value *Arg1 = BO->getOperand(1); + // We allow matching the canonical IR (add X, C) back to (usubo X, -C). if (BO->getOpcode() == Instruction::Add && IID == Intrinsic::usub_with_overflow) { assert(isa(Arg1) && "Unexpected input for usubo"); Arg1 = ConstantExpr::getNeg(cast(Arg1)); + } else if (BO->getOpcode() == Instruction::Xor) { + Arg0 = BO->getOperand(0); + Arg1 = Cmp->getOperand(1); } // Insert at the first instruction of the pair. diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -5572,8 +5572,11 @@ isa(A->getType())) { Value *Result; Constant *Overflow; - if (OptimizeOverflowCheck(Instruction::Add, /*Signed*/false, A, B, - *AddI, Result, Overflow)) { + // m_UAddWithOverflow can match patterns that do not include an explicit + // "add" instruction, so check the opcode of the matched op. + if (AddI->getOpcode() == Instruction::Add && + OptimizeOverflowCheck(Instruction::Add, /*Signed*/ false, A, B, *AddI, + Result, Overflow)) { replaceInstUsesWith(*AddI, Result); return replaceInstUsesWith(I, Overflow); } diff --git a/llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll b/llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll --- a/llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll +++ b/llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll @@ -102,9 +102,10 @@ ; pattern as well. define i64 @uaddo6_xor(i64 %a, i64 %b) { ; CHECK-LABEL: @uaddo6_xor( -; CHECK-NEXT: [[X:%.*]] = xor i64 [[A:%.*]], -1 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X]], [[B:%.*]] -; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 +; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) +; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0 +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1 +; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %x = xor i64 %a, -1 @@ -115,9 +116,10 @@ define i64 @uaddo6_xor_commuted(i64 %a, i64 %b) { ; CHECK-LABEL: @uaddo6_xor_commuted( -; CHECK-NEXT: [[X:%.*]] = xor i64 -1, [[A:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X]], [[B:%.*]] -; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 +; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 -1, i64 [[B:%.*]]) +; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0 +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1 +; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %x = xor i64 -1, %a diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll b/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll --- a/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll +++ b/llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll @@ -153,9 +153,10 @@ ; pattern as well. define i64 @uaddo6_xor(i64 %a, i64 %b) { ; CHECK-LABEL: @uaddo6_xor( -; CHECK-NEXT: [[X:%.*]] = xor i64 [[A:%.*]], -1 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X]], [[B:%.*]] -; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 +; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]]) +; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0 +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1 +; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %x = xor i64 %a, -1 @@ -166,9 +167,10 @@ define i64 @uaddo6_xor_commuted(i64 %a, i64 %b) { ; CHECK-LABEL: @uaddo6_xor_commuted( -; CHECK-NEXT: [[X:%.*]] = xor i64 -1, [[A:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[X]], [[B:%.*]] -; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 +; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 -1, i64 [[B:%.*]]) +; CHECK-NEXT: [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0 +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1 +; CHECK-NEXT: [[Q:%.*]] = select i1 [[OV]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %x = xor i64 -1, %a