diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -2676,17 +2676,21 @@ /// node operation. Targets may want to override this independently of whether /// the operation is legal/custom for the given type because it may obscure /// matching of other patterns. - virtual bool shouldFormOverflowOp(unsigned Opcode, EVT VT) const { + virtual bool shouldFormOverflowOp(unsigned Opcode, EVT VT, + bool MathUsed) const { // TODO: The default logic is inherited from code in CodeGenPrepare. // The opcode should not make a difference by default? if (Opcode != ISD::UADDO) return false; // Allow the transform as long as we have an integer type that is not - // obviously illegal and unsupported. + // obviously illegal and unsupported and if the math result is used + // besides the overflow check. On some targets (e.g. SPARC), it is + // not profitable to form on overflow op if the math result has no + // concrete users. if (VT.isVector()) return false; - return VT.isSimple() || !isOperationExpand(Opcode, VT); + return MathUsed && (VT.isSimple() || !isOperationExpand(Opcode, VT)); } // Return true if it is profitable to use a scalar input to a BUILD_VECTOR diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1272,7 +1272,8 @@ return false; if (!TLI->shouldFormOverflowOp(ISD::UADDO, - TLI->getValueType(*DL, Add->getType()))) + TLI->getValueType(*DL, Add->getType()), + Add->hasNUsesOrMore(2))) return false; // We don't want to move around uses of condition values this late, so we @@ -1339,7 +1340,8 @@ return false; if (!TLI->shouldFormOverflowOp(ISD::USUBO, - TLI->getValueType(*DL, Sub->getType()))) + TLI->getValueType(*DL, Sub->getType()), + Sub->hasNUsesOrMore(2))) return false; if (!replaceMathCmpWithIntrinsic(Sub, Cmp, Intrinsic::usub_with_overflow)) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -471,6 +471,13 @@ bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, unsigned Index) const override; + bool shouldFormOverflowOp(unsigned Opcode, EVT VT, + bool MathUsed) const override { + // Using overflow ops for overflow checks only should beneficial on + // AArch64. + return TargetLowering::shouldFormOverflowOp(Opcode, VT, true); + } + Value *emitLoadLinked(IRBuilder<> &Builder, Value *Addr, AtomicOrdering Ord) const override; Value *emitStoreConditional(IRBuilder<> &Builder, Value *Val, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -524,6 +524,12 @@ bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, unsigned Index) const override; + bool shouldFormOverflowOp(unsigned Opcode, EVT VT, + bool MathUsed) const override { + // Using overflow ops for overflow checks only should beneficial on ARM. + return TargetLowering::shouldFormOverflowOp(Opcode, VT, true); + } + /// Returns true if an argument of type Ty needs to be passed in a /// contiguous block of registers in calling convention CallConv. bool functionArgumentNeedsConsecutiveRegisters( diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -439,6 +439,14 @@ bool *Fast) const override; bool isTruncateFree(Type *, Type *) const override; bool isTruncateFree(EVT, EVT) const override; + + bool shouldFormOverflowOp(unsigned Opcode, EVT VT, + bool MathUsed) const override { + // Using overflow ops for overflow checks only should beneficial on + // SystemZ. + return TargetLowering::shouldFormOverflowOp(Opcode, VT, true); + } + const char *getTargetNodeName(unsigned Opcode) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -1150,7 +1150,8 @@ /// Overflow nodes should get combined/lowered to optimal instructions /// (they should allow eliminating explicit compares by getting flags from /// math ops). - bool shouldFormOverflowOp(unsigned Opcode, EVT VT) const override; + bool shouldFormOverflowOp(unsigned Opcode, EVT VT, + bool MathUsed) const override; bool storeOfVectorConstantIsCheap(EVT MemVT, unsigned NumElem, unsigned AddrSpace) const override { diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -5168,7 +5168,8 @@ return isOperationLegalOrCustomOrPromote(Opc, ScalarVT); } -bool X86TargetLowering::shouldFormOverflowOp(unsigned Opcode, EVT VT) const { +bool X86TargetLowering::shouldFormOverflowOp(unsigned Opcode, EVT VT, + bool) const { // TODO: Allow vectors? if (VT.isVector()) return false; diff --git a/llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll b/llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll --- a/llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll +++ b/llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll @@ -10,10 +10,9 @@ define i64 @uaddo1_overflow_used(i64 %a, i64 %b) nounwind ssp { ; CHECK-LABEL: @uaddo1_overflow_used( -; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]]) -; 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: [[ADD:%.*]] = add i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[ADD]], [[A]] +; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %add = add i64 %b, %a @@ -40,10 +39,9 @@ define i64 @uaddo2_overflow_used(i64 %a, i64 %b) nounwind ssp { ; CHECK-LABEL: @uaddo2_overflow_used( -; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]]) -; 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: [[ADD:%.*]] = add i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[ADD]], [[B]] +; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %add = add i64 %b, %a @@ -70,10 +68,9 @@ define i64 @uaddo3_overflow_used(i64 %a, i64 %b) nounwind ssp { ; CHECK-LABEL: @uaddo3_overflow_used( -; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]]) -; 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: [[ADD:%.*]] = add i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[B]], [[ADD]] +; CHECK-NEXT: [[Q:%.*]] = select i1 [[CMP]], i64 [[B]], i64 42 ; CHECK-NEXT: ret i64 [[Q]] ; %add = add i64 %b, %a