diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index fb48c6466a49..d932b57f2449 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -2486,14 +2486,24 @@ bool X86DAGToDAGISel::shrinkAndImmediate(SDNode *And) { if (!And1C) return false; - // Bail out if the mask constant is already negative. It can't shrink more. + // Bail out if the mask constant is already negative. It's can't shrink more. + // If the upper 32 bits of a 64 bit mask are all zeros, we have special isel + // patterns to use a 32-bit and instead of a 64-bit and by relying on the + // implicit zeroing of 32 bit ops. So we should check if the lower 32 bits + // are negative too. APInt MaskVal = And1C->getAPIntValue(); unsigned MaskLZ = MaskVal.countLeadingZeros(); - if (!MaskLZ) + if (!MaskLZ || (VT == MVT::i64 && MaskLZ == 32)) return false; + // Don't extend into the upper 32 bits of a 64 bit mask. + if (VT == MVT::i64 && MaskLZ >= 32) { + MaskLZ -= 32; + MaskVal = MaskVal.trunc(32); + } + SDValue And0 = And->getOperand(0); - APInt HighZeros = APInt::getHighBitsSet(VT.getSizeInBits(), MaskLZ); + APInt HighZeros = APInt::getHighBitsSet(MaskVal.getBitWidth(), MaskLZ); APInt NegMaskVal = MaskVal | HighZeros; // If a negative constant would not allow a smaller encoding, there's no need @@ -2502,6 +2512,12 @@ bool X86DAGToDAGISel::shrinkAndImmediate(SDNode *And) { if (MinWidth > 32 || (MinWidth > 8 && MaskVal.getMinSignedBits() <= 32)) return false; + // Extend masks if we truncated above. + if (VT == MVT::i64 && MaskVal.getBitWidth() < 64) { + NegMaskVal = NegMaskVal.zext(64); + HighZeros = HighZeros.zext(64); + } + // The variable operand must be all zeros in the top bits to allow using the // new, negative constant as the mask. if (!CurDAG->MaskedValueIsZero(And0, HighZeros)) diff --git a/llvm/test/CodeGen/X86/and-encoding.ll b/llvm/test/CodeGen/X86/and-encoding.ll index fe57842b94e5..51cdbd9f6e11 100644 --- a/llvm/test/CodeGen/X86/and-encoding.ll +++ b/llvm/test/CodeGen/X86/and-encoding.ll @@ -61,7 +61,7 @@ define i64 @lopped64_32to8(i64 %x) { ; CHECK-LABEL: lopped64_32to8: ; CHECK: # %bb.0: ; CHECK-NEXT: shrq $36, %rdi # encoding: [0x48,0xc1,0xef,0x24] -; CHECK-NEXT: andq $-16, %rdi # encoding: [0x48,0x83,0xe7,0xf0] +; CHECK-NEXT: andl $-16, %edi # encoding: [0x83,0xe7,0xf0] ; CHECK-NEXT: movq %rdi, %rax # encoding: [0x48,0x89,0xf8] ; CHECK-NEXT: retq # encoding: [0xc3] %shr = lshr i64 %x, 36 diff --git a/llvm/test/CodeGen/X86/shift-pair.ll b/llvm/test/CodeGen/X86/shift-pair.ll index 0823190451b0..0a1d68db34f8 100644 --- a/llvm/test/CodeGen/X86/shift-pair.ll +++ b/llvm/test/CodeGen/X86/shift-pair.ll @@ -5,7 +5,7 @@ define i64 @test(i64 %A) { ; CHECK-LABEL: test: ; CHECK: # %bb.0: ; CHECK-NEXT: shrq $54, %rdi -; CHECK-NEXT: andq $-4, %rdi +; CHECK-NEXT: andl $-4, %edi ; CHECK-NEXT: movq %rdi, %rax ; CHECK-NEXT: retq %B = lshr i64 %A, 56