Index: llvm/lib/Target/X86/X86ISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -2634,10 +2634,13 @@ return false; bool IsCommutable = false; + bool IsNegate = false; switch (Opc) { default: return false; case X86ISD::SUB: + IsNegate = isNullConstant(StoredVal.getOperand(0)); + break; case X86ISD::SBB: break; case X86ISD::ADD: @@ -2649,7 +2652,7 @@ break; } - unsigned LoadOpNo = 0; + unsigned LoadOpNo = IsNegate ? 1 : 0; LoadSDNode *LoadNode = nullptr; SDValue InputChain; if (!isFusableLoadOpStorePattern(StoreNode, StoredVal, CurDAG, LoadOpNo, @@ -2687,8 +2690,18 @@ MachineSDNode *Result; switch (Opc) { - case X86ISD::ADD: case X86ISD::SUB: + // Handle negate. + if (IsNegate) { + unsigned NewOpc = SelectOpcode(X86::NEG64m, X86::NEG32m, X86::NEG16m, + X86::NEG8m); + const SDValue Ops[] = {Base, Scale, Index, Disp, Segment, InputChain}; + Result = CurDAG->getMachineNode(NewOpc, SDLoc(Node), MVT::i32, + MVT::Other, Ops); + break; + } + LLVM_FALLTHROUGH; + case X86ISD::ADD: // Try to match inc/dec. if (!Subtarget->slowIncDec() || OptForSize) { bool IsOne = isOneConstant(StoredVal.getOperand(1)); Index: llvm/test/CodeGen/X86/fold-rmw-ops.ll =================================================================== --- llvm/test/CodeGen/X86/fold-rmw-ops.ll +++ llvm/test/CodeGen/X86/fold-rmw-ops.ll @@ -2434,10 +2434,7 @@ define void @neg64_br() nounwind { ; CHECK-LABEL: neg64_br: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0] -; CHECK-NEXT: subq {{.*}}(%rip), %rax # encoding: [0x48,0x2b,0x05,A,A,A,A] -; CHECK-NEXT: # fixup A - offset: 3, value: g64-4, kind: reloc_riprel_4byte_relax_rex -; CHECK-NEXT: movq %rax, {{.*}}(%rip) # encoding: [0x48,0x89,0x05,A,A,A,A] +; CHECK-NEXT: negq {{.*}}(%rip) # encoding: [0x48,0xf7,0x1d,A,A,A,A] ; CHECK-NEXT: # fixup A - offset: 3, value: g64-4, kind: reloc_riprel_4byte ; CHECK-NEXT: js .LBB76_1 # encoding: [0x78,A] ; CHECK-NEXT: # fixup A - offset: 1, value: .LBB76_1-1, kind: FK_PCRel_1 @@ -2468,10 +2465,7 @@ define void @neg32_br() nounwind { ; CHECK-LABEL: neg32_br: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0] -; CHECK-NEXT: subl {{.*}}(%rip), %eax # encoding: [0x2b,0x05,A,A,A,A] -; CHECK-NEXT: # fixup A - offset: 2, value: g32-4, kind: reloc_riprel_4byte -; CHECK-NEXT: movl %eax, {{.*}}(%rip) # encoding: [0x89,0x05,A,A,A,A] +; CHECK-NEXT: negl {{.*}}(%rip) # encoding: [0xf7,0x1d,A,A,A,A] ; CHECK-NEXT: # fixup A - offset: 2, value: g32-4, kind: reloc_riprel_4byte ; CHECK-NEXT: js .LBB77_1 # encoding: [0x78,A] ; CHECK-NEXT: # fixup A - offset: 1, value: .LBB77_1-1, kind: FK_PCRel_1 @@ -2502,10 +2496,7 @@ define void @neg16_br() nounwind { ; CHECK-LABEL: neg16_br: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0] -; CHECK-NEXT: subw {{.*}}(%rip), %ax # encoding: [0x66,0x2b,0x05,A,A,A,A] -; CHECK-NEXT: # fixup A - offset: 3, value: g16-4, kind: reloc_riprel_4byte -; CHECK-NEXT: movw %ax, {{.*}}(%rip) # encoding: [0x66,0x89,0x05,A,A,A,A] +; CHECK-NEXT: negw {{.*}}(%rip) # encoding: [0x66,0xf7,0x1d,A,A,A,A] ; CHECK-NEXT: # fixup A - offset: 3, value: g16-4, kind: reloc_riprel_4byte ; CHECK-NEXT: js .LBB78_1 # encoding: [0x78,A] ; CHECK-NEXT: # fixup A - offset: 1, value: .LBB78_1-1, kind: FK_PCRel_1 @@ -2536,10 +2527,7 @@ define void @neg8_br() nounwind { ; CHECK-LABEL: neg8_br: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0] -; CHECK-NEXT: subb {{.*}}(%rip), %al # encoding: [0x2a,0x05,A,A,A,A] -; CHECK-NEXT: # fixup A - offset: 2, value: g8-4, kind: reloc_riprel_4byte -; CHECK-NEXT: movb %al, {{.*}}(%rip) # encoding: [0x88,0x05,A,A,A,A] +; CHECK-NEXT: negb {{.*}}(%rip) # encoding: [0xf6,0x1d,A,A,A,A] ; CHECK-NEXT: # fixup A - offset: 2, value: g8-4, kind: reloc_riprel_4byte ; CHECK-NEXT: js .LBB79_1 # encoding: [0x78,A] ; CHECK-NEXT: # fixup A - offset: 1, value: .LBB79_1-1, kind: FK_PCRel_1