diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index eafa95ce7fcf71..bb44ac1fba486d 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -7987,7 +7987,7 @@ SDValue DAGCombiner::visitOR(SDNode *N) { // If OR can be rewritten into ADD, try combines based on ADD. if ((!LegalOperations || TLI.isOperationLegal(ISD::ADD, VT)) && - DAG.haveNoCommonBitsSet(N0, N1)) + DAG.isADDLike(SDValue(N, 0))) if (SDValue Combined = visitADDLike(N)) return Combined; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 75c10a74cdc44c..4151964adc7db1 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -5088,7 +5088,8 @@ bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, bool SelectionDAG::isADDLike(SDValue Op) const { unsigned Opcode = Op.getOpcode(); if (Opcode == ISD::OR) - return haveNoCommonBitsSet(Op.getOperand(0), Op.getOperand(1)); + return Op->getFlags().hasDisjoint() || + haveNoCommonBitsSet(Op.getOperand(0), Op.getOperand(1)); if (Opcode == ISD::XOR) return isMinSignedConstant(Op.getOperand(1)); return false; diff --git a/llvm/test/CodeGen/X86/addsub-constant-folding.ll b/llvm/test/CodeGen/X86/addsub-constant-folding.ll index de215c80dcd1a9..4dbaae5c1a74ae 100644 --- a/llvm/test/CodeGen/X86/addsub-constant-folding.ll +++ b/llvm/test/CodeGen/X86/addsub-constant-folding.ll @@ -1141,3 +1141,39 @@ define <4 x i32> @vec_const_sub_const_sub_nonsplat(<4 x i32> %arg) { %t1 = sub <4 x i32> , %t0 ret <4 x i32> %t1 } + +; (x|c1)+c2 where (x|c1) is addlike +define i32 @add_const_disjoint_or_const(i32 %arg) { +; X86-LABEL: add_const_disjoint_or_const: +; X86: # %bb.0: +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: addl $10, %eax +; X86-NEXT: retl +; +; X64-LABEL: add_const_disjoint_or_const: +; X64: # %bb.0: +; X64-NEXT: # kill: def $edi killed $edi def $rdi +; X64-NEXT: leal 10(%rdi), %eax +; X64-NEXT: retq + %t0 = or disjoint i32 %arg, 8 + %t1 = add i32 %t0, 2 + ret i32 %t1 +} + +; (x+c1)|c2 where the outer or is addlike +define i32 @disjoint_or_const_add_const(i32 %arg) { +; X86-LABEL: disjoint_or_const_add_const: +; X86: # %bb.0: +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: addl $10, %eax +; X86-NEXT: retl +; +; X64-LABEL: disjoint_or_const_add_const: +; X64: # %bb.0: +; X64-NEXT: # kill: def $edi killed $edi def $rdi +; X64-NEXT: leal 10(%rdi), %eax +; X64-NEXT: retq + %t0 = add i32 %arg, 8 + %t1 = or disjoint i32 %t0, 2 + ret i32 %t1 +} diff --git a/llvm/test/CodeGen/X86/or-lea.ll b/llvm/test/CodeGen/X86/or-lea.ll index ab9b917803248e..616ab994378927 100644 --- a/llvm/test/CodeGen/X86/or-lea.ll +++ b/llvm/test/CodeGen/X86/or-lea.ll @@ -825,3 +825,23 @@ entry: %or = or i64 %sub, 549755813889 ; 0x8000000001 ret i64 %or } + +define i32 @or_shift1_disjoint(i32 %x, i32 %y) { +; X86-LABEL: or_shift1_disjoint: +; X86: # %bb.0: +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: addl %eax, %eax +; X86-NEXT: orl {{[0-9]+}}(%esp), %eax +; X86-NEXT: retl +; +; X64-LABEL: or_shift1_disjoint: +; X64: # %bb.0: +; X64-NEXT: # kill: def $esi killed $esi def $rsi +; X64-NEXT: # kill: def $edi killed $edi def $rdi +; X64-NEXT: leal (%rsi,%rdi,2), %eax +; X64-NEXT: retq + %shl = shl i32 %x, 1 + %or = or disjoint i32 %y, %shl + ret i32 %or +} +