diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -4063,8 +4063,10 @@ unsigned BitWidth = OpVT.getScalarSizeInBits(); // Is the constant a known power of 2? - if (ConstantSDNode *Const = dyn_cast(Val)) - return Const->getAPIntValue().zextOrTrunc(BitWidth).isPowerOf2(); + if (ISD::matchUnaryPredicate(Val, [BitWidth](ConstantSDNode *C) { + return C->getAPIntValue().zextOrTrunc(BitWidth).isPowerOf2(); + })) + return true; // A left-shift of a constant one will have exactly one bit set because // shifting the bit off the end is undefined. @@ -4072,6 +4074,8 @@ auto *C = isConstOrConstSplat(Val.getOperand(0)); if (C && C->getAPIntValue() == 1) return true; + return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1) && + isKnownNeverZero(Val, Depth); } // Similarly, a logical right-shift of a constant sign-bit will have exactly @@ -4080,8 +4084,13 @@ auto *C = isConstOrConstSplat(Val.getOperand(0)); if (C && C->getAPIntValue().isSignMask()) return true; + return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1) && + isKnownNeverZero(Val, Depth); } + if (Val.getOpcode() == ISD::ROTL || Val.getOpcode() == ISD::ROTR) + return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); + // Are all operands of a build vector constant powers of two? if (Val.getOpcode() == ISD::BUILD_VECTOR) if (llvm::all_of(Val->ops(), [BitWidth](SDValue E) { @@ -4103,6 +4112,34 @@ isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1)) return true; + if (Val.getOpcode() == ISD::SMIN || Val.getOpcode() == ISD::SMAX || + Val.getOpcode() == ISD::UMIN || Val.getOpcode() == ISD::UMAX) + return isKnownToBeAPowerOfTwo(Val.getOperand(1), Depth + 1) && + isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); + + if (Val.getOpcode() == ISD::SELECT || Val.getOpcode() == ISD::VSELECT) + return isKnownToBeAPowerOfTwo(Val.getOperand(2), Depth + 1) && + isKnownToBeAPowerOfTwo(Val.getOperand(1), Depth + 1); + + if (Val.getOpcode() == ISD::AND) { + // Looking for `x & -x` pattern: + // If x == 0: + // x & -x -> 0 + // If x != 0: + // x & -x -> non-zero pow2 + // so if we find the pattern return whether we know `x` is non-zero. + for (unsigned OpIdx = 0; OpIdx < 2; ++OpIdx) { + SDValue NegOp = Val.getOperand(OpIdx); + if (NegOp.getOpcode() == ISD::SUB && + NegOp.getOperand(1) == Val.getOperand(1 - OpIdx) && + isNullOrNullSplat(NegOp.getOperand(0))) + return isKnownNeverZero(Val.getOperand(1 - OpIdx), Depth); + } + } + + if (Val.getOpcode() == ISD::ZERO_EXTEND) + return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); + // More could be done here, though the above checks are enough // to handle some common cases. return false; diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll --- a/llvm/test/CodeGen/X86/known-pow2.ll +++ b/llvm/test/CodeGen/X86/known-pow2.ll @@ -50,11 +50,12 @@ ; CHECK-LABEL: pow2_shl: ; CHECK: # %bb.0: ; CHECK-NEXT: movl %esi, %ecx -; CHECK-NEXT: notl %edi +; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx -; CHECK-NEXT: shrl %cl, %edi -; CHECK-NEXT: testb $4, %dil -; CHECK-NEXT: sete %al +; CHECK-NEXT: shrl %cl, %eax +; CHECK-NEXT: andl $4, %eax +; CHECK-NEXT: shrl $2, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax ; CHECK-NEXT: retq %d = shl nuw nsw i32 4, %y %and = and i32 %x, %d @@ -98,12 +99,13 @@ ; CHECK-LABEL: pow2_srl: ; CHECK: # %bb.0: ; CHECK-NEXT: movl %esi, %ecx +; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: andb $7, %cl -; CHECK-NEXT: notl %edi ; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx -; CHECK-NEXT: shll %cl, %edi -; CHECK-NEXT: testl $1048576, %edi # imm = 0x100000 -; CHECK-NEXT: sete %al +; CHECK-NEXT: shll %cl, %eax +; CHECK-NEXT: shrl $20, %eax +; CHECK-NEXT: andl $1, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax ; CHECK-NEXT: retq %yy = and i32 %y, 7 %d = lshr i32 1048576, %yy @@ -155,9 +157,8 @@ ; CHECK-NEXT: movl $1048576, %eax # imm = 0x100000 ; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx ; CHECK-NEXT: roll %cl, %eax -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %eax -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %eax, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %d = call i32 @llvm.fshl.i32(i32 1048576, i32 1048576, i32 %y) %and = and i32 %x, %d @@ -207,9 +208,8 @@ ; CHECK-NEXT: movl $1048576, %eax # imm = 0x100000 ; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx ; CHECK-NEXT: rorl %cl, %eax -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %eax -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %eax, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %d = call i32 @llvm.fshr.i32(i32 1048576, i32 1048576, i32 %y) %and = and i32 %x, %d @@ -262,9 +262,8 @@ ; CHECK-NEXT: cmpl $262144, %eax # imm = 0x40000 ; CHECK-NEXT: movl $262144, %ecx # imm = 0x40000 ; CHECK-NEXT: cmovbl %eax, %ecx -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %ecx -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %ecx, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %yy = shl i32 1, %y %d = call i32 @llvm.umin.i32(i32 %yy, i32 262144) @@ -327,9 +326,8 @@ ; CHECK-NEXT: shrl %cl, %esi ; CHECK-NEXT: cmpl %esi, %eax ; CHECK-NEXT: cmoval %eax, %esi -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %esi -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %esi, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %yy = shl i32 1, %y %zz = lshr i32 2147483648, %z @@ -397,9 +395,8 @@ ; CHECK-NEXT: cmpl $262144, %eax # imm = 0x40000 ; CHECK-NEXT: movl $262144, %ecx # imm = 0x40000 ; CHECK-NEXT: cmovll %eax, %ecx -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %ecx -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %ecx, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %yy = shl i32 1, %y %d = call i32 @llvm.smin.i32(i32 %yy, i32 262144) @@ -462,9 +459,8 @@ ; CHECK-NEXT: shrl %cl, %esi ; CHECK-NEXT: cmpl %esi, %eax ; CHECK-NEXT: cmovgl %eax, %esi -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %esi -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %esi, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %yy = shl i32 1, %y %zz = lshr i32 2147483648, %z @@ -535,9 +531,8 @@ ; CHECK-NEXT: shrl %cl, %r8d ; CHECK-NEXT: testb $1, %dil ; CHECK-NEXT: cmovnel %edx, %r8d -; CHECK-NEXT: notl %esi -; CHECK-NEXT: testl %esi, %r8d -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %r8d, %esi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %yy = shl i32 1, %y %zz = lshr i32 2147483648, %z @@ -624,8 +619,11 @@ ; CHECK-NEXT: pand %xmm0, %xmm2 ; CHECK-NEXT: pandn %xmm7, %xmm0 ; CHECK-NEXT: por %xmm2, %xmm0 -; CHECK-NEXT: pand %xmm0, %xmm1 +; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 +; CHECK-NEXT: pand %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm1, %xmm1 ; CHECK-NEXT: pcmpeqd %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm2, %xmm0 ; CHECK-NEXT: retq %yy = shl <4 x i32> , %y %zz = lshr <4 x i32> , %z @@ -662,10 +660,9 @@ ; CHECK-NEXT: pand %xmm0, %xmm2 ; CHECK-NEXT: pandn %xmm7, %xmm0 ; CHECK-NEXT: por %xmm2, %xmm0 -; CHECK-NEXT: pcmpeqd %xmm2, %xmm2 -; CHECK-NEXT: pand %xmm0, %xmm1 +; CHECK-NEXT: pand %xmm1, %xmm0 +; CHECK-NEXT: pxor %xmm1, %xmm1 ; CHECK-NEXT: pcmpeqd %xmm1, %xmm0 -; CHECK-NEXT: pxor %xmm2, %xmm0 ; CHECK-NEXT: retq %yy = shl <4 x i32> , %y %zz = lshr <4 x i32> , %z @@ -772,9 +769,8 @@ ; CHECK-NEXT: movl %eax, %ecx ; CHECK-NEXT: negl %ecx ; CHECK-NEXT: andl %eax, %ecx -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %edi, %ecx -; CHECK-NEXT: sete %al +; CHECK-NEXT: testl %ecx, %edi +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %yy = shl nuw nsw i32 4, %y %nyy = sub i32 0, %yy @@ -854,10 +850,9 @@ ; CHECK-NEXT: movl $4, %eax ; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx ; CHECK-NEXT: shll %cl, %eax -; CHECK-NEXT: notl %edi -; CHECK-NEXT: andl %eax, %edi -; CHECK-NEXT: testl $65535, %edi # imm = 0xFFFF -; CHECK-NEXT: sete %al +; CHECK-NEXT: andl %edi, %eax +; CHECK-NEXT: testl $65535, %eax # imm = 0xFFFF +; CHECK-NEXT: setne %al ; CHECK-NEXT: retq %dd = shl nuw nsw i16 4, %y %d = zext i16 %dd to i32