diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index b59d4a8618220..f70adfee64fea 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -58070,8 +58070,28 @@ static SDValue combineAdd(SDNode *N, SelectionDAG &DAG, EVT VT = N->getValueType(0); SDValue Op0 = N->getOperand(0); SDValue Op1 = N->getOperand(1); + unsigned int Opcode = N->getOpcode(); SDLoc DL(N); + // Use a 32-bit add+zext if upper 33 bits known zero. + if (VT == MVT::i64 && Subtarget.is64Bit()) { + APInt HiMask = APInt::getHighBitsSet(64, 33); + if (DAG.MaskedValueIsZero(Op0, HiMask) && + DAG.MaskedValueIsZero(Op1, HiMask)) { + SDValue LHS = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Op0); + SDValue RHS = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Op1); + bool NSW = Op0->getFlags().hasNoSignedWrap(); + bool NUW = Op0->getFlags().hasNoUnsignedWrap(); + NSW = NSW & DAG.willNotOverflowAdd(true, LHS, RHS); + NUW = NUW & DAG.willNotOverflowAdd(false, LHS, RHS); + SDNodeFlags Flags; + Flags.setNoUnsignedWrap(NUW); + Flags.setNoSignedWrap(NSW); + SDValue Sum = DAG.getNode(Opcode, DL, MVT::i32, LHS, RHS, Flags); + return DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Sum); + } + } + if (SDValue Select = pushAddIntoCmovOfConsts(N, DL, DAG, Subtarget)) return Select; diff --git a/llvm/test/CodeGen/X86/reduce-i64-add.ll b/llvm/test/CodeGen/X86/reduce-i64-add.ll new file mode 100644 index 0000000000000..a9399a0dd26eb --- /dev/null +++ b/llvm/test/CodeGen/X86/reduce-i64-add.ll @@ -0,0 +1,31 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefix=X86 +; RUN: llc < %s -mtriple=x86_64-linux -verify-machineinstrs | FileCheck %s --check-prefix=X64-LINUX +; RUN: llc < %s -mtriple=x86_64-win32 | FileCheck %s --check-prefix=X64-WIN32 + +define i64 @test1(i16 %x) nounwind { +; X86-LABEL: test1: +; X86: # %bb.0: # %entry +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: addl $42, %eax +; X86-NEXT: movzwl %ax, %eax +; X86-NEXT: xorl %edx, %edx +; X86-NEXT: retl +; +; X64-LINUX-LABEL: test1: +; X64-LINUX: # %bb.0: # %entry +; X64-LINUX-NEXT: addl $42, %edi +; X64-LINUX-NEXT: movzwl %di, %eax +; X64-LINUX-NEXT: retq +; +; X64-WIN32-LABEL: test1: +; X64-WIN32: # %bb.0: # %entry +; X64-WIN32-NEXT: # kill: def $cx killed $cx def $ecx +; X64-WIN32-NEXT: addl $42, %ecx +; X64-WIN32-NEXT: movzwl %cx, %eax +; X64-WIN32-NEXT: retq +entry: + %add = add nuw nsw i16 %x, 42 + %conv = zext i16 %add to i64 + ret i64 %conv +}