Index: llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -6882,6 +6882,8 @@ // (and (srl x, (sub c1, c2), MASK) // Only fold this if the inner shift has no other uses -- if it does, folding // this will increase the total number of instructions. + // TODO - drop hasOneUse requirement if c1 == c2? + // TODO - support non-uniform vector shift amounts. if (N1C && N0.getOpcode() == ISD::SRL && N0.hasOneUse() && TLI.shouldFoldConstantShiftPairToMask(N, Level)) { if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) { @@ -7188,6 +7190,7 @@ } // fold (srl (shl x, c), c) -> (and x, cst2) + // TODO - (srl (shl x, c1), c2). if (N0.getOpcode() == ISD::SHL && N0.getOperand(1) == N1 && isConstantOrConstantVector(N1, /* NoOpaques */ true)) { SDLoc DL(N); Index: llvm/trunk/lib/Target/X86/X86.td =================================================================== --- llvm/trunk/lib/Target/X86/X86.td +++ llvm/trunk/lib/Target/X86/X86.td @@ -424,6 +424,11 @@ "Prefer horizontal vector math instructions (haddp, phsub, etc.) over " "normal vector instructions with shuffles", [FeatureSSE3]>; +def FeatureFastVectorShiftMasks + : SubtargetFeature< + "fast-vector-shift-masks", "HasFastVectorShiftMasks", "true", + "Prefer a left/right vector logical shift pair over a shift+and pair">; + // Merge branches using three-way conditional code. def FeatureMergeToThreeWayBranch : SubtargetFeature<"merge-to-threeway-branch", "ThreewayBranchProfitable", "true", @@ -775,7 +780,8 @@ FeaturePOPCNT, FeatureSlowSHLD, FeatureLAHFSAHF, - FeatureFast15ByteNOP]; + FeatureFast15ByteNOP, + FeatureFastVectorShiftMasks]; list BtVer1Features = BtVer1InheritableFeatures; // Jaguar Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -5013,7 +5013,18 @@ bool X86TargetLowering::shouldFoldConstantShiftPairToMask( const SDNode *N, CombineLevel Level) const { - // TODO - some targets prefer immediate vector shifts to shift+mask. + assert((N->getOpcode() == ISD::SHL && + N->getOperand(0).getOpcode() == ISD::SRL) || + (N->getOpcode() == ISD::SRL && + N->getOperand(0).getOpcode() == ISD::SHL) && + "Expected shift-shift mask"); + + if (Subtarget.hasFastVectorShiftMasks() && N->getValueType(0).isVector()) { + // Only fold if the shift values are equal - so it folds to AND. + // TODO - we should fold if either is non-uniform but we don't do the + // fold for non-splats yet. + return N->getOperand(1) == N->getOperand(0).getOperand(1); + } return TargetLoweringBase::shouldFoldConstantShiftPairToMask(N, Level); } Index: llvm/trunk/lib/Target/X86/X86Subtarget.h =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.h +++ llvm/trunk/lib/Target/X86/X86Subtarget.h @@ -393,6 +393,9 @@ /// Try harder to combine to horizontal vector ops if they are fast. bool HasFastHorizontalOps = false; + /// Prefer a left/right vector logical shifts pair over a shift+and pair. + bool HasFastVectorShiftMasks = false; + /// Use a retpoline thunk rather than indirect calls to block speculative /// execution. bool UseRetpolineIndirectCalls = false; @@ -644,6 +647,7 @@ bool hasFastSHLDRotate() const { return HasFastSHLDRotate; } bool hasFastBEXTR() const { return HasFastBEXTR; } bool hasFastHorizontalOps() const { return HasFastHorizontalOps; } + bool hasFastVectorShiftMasks() const { return HasFastVectorShiftMasks; } bool hasMacroFusion() const { return HasMacroFusion; } bool hasBranchFusion() const { return HasBranchFusion; } bool hasERMSB() const { return HasERMSB; } Index: llvm/trunk/test/CodeGen/X86/sse2-vector-shifts.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/sse2-vector-shifts.ll +++ llvm/trunk/test/CodeGen/X86/sse2-vector-shifts.ll @@ -1,5 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc < %s -mtriple=x86_64-pc-linux -mattr=+sse2 | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-pc-linux -mattr=+sse2 | FileCheck %s --check-prefixes=CHECK,MASK +; RUN: llc < %s -mtriple=x86_64-pc-linux -mattr=+sse2,+fast-vector-shift-masks | FileCheck %s --check-prefixes=CHECK,SHIFT +; RUN: llc < %s -mtriple=x86_64-pc-linux -mcpu=btver1 | FileCheck %s --check-prefixes=CHECK,SHIFT ; SSE2 Logical Shift Left @@ -300,11 +302,17 @@ } define <4 x i32> @shl_srl_v4i32(<4 x i32> %x) nounwind { -; CHECK-LABEL: shl_srl_v4i32: -; CHECK: # %bb.0: -; CHECK-NEXT: pslld $3, %xmm0 -; CHECK-NEXT: pand {{.*}}(%rip), %xmm0 -; CHECK-NEXT: retq +; MASK-LABEL: shl_srl_v4i32: +; MASK: # %bb.0: +; MASK-NEXT: pslld $3, %xmm0 +; MASK-NEXT: pand {{.*}}(%rip), %xmm0 +; MASK-NEXT: retq +; +; SHIFT-LABEL: shl_srl_v4i32: +; SHIFT: # %bb.0: +; SHIFT-NEXT: psrld $2, %xmm0 +; SHIFT-NEXT: pslld $5, %xmm0 +; SHIFT-NEXT: retq %shl0 = lshr <4 x i32> %x, %shl1 = shl <4 x i32> %shl0, ret <4 x i32> %shl1