diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 739c1448cdf..ba6c9c06db0 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -13693,6 +13693,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const { case X86ISD::BLSMSK: return "X86ISD::BLSMSK"; case X86ISD::BLSR: return "X86ISD::BLSR"; case X86ISD::BZHI: return "X86ISD::BZHI"; + case X86ISD::BEXTR: return "X86ISD::BEXTR"; case X86ISD::MUL_IMM: return "X86ISD::MUL_IMM"; case X86ISD::PTEST: return "X86ISD::PTEST"; case X86ISD::TESTP: return "X86ISD::TESTP"; @@ -17503,6 +17504,7 @@ static SDValue PerformAndCombine(SDNode *N, SelectionDAG &DAG, // BLSI is X & (-X) // BLSR is X & (X-1) // BZHI is X & ((1 << Y) - 1) + // BEXTR is ((X >> imm) & (2**size-1)) if (VT == MVT::i32 || VT == MVT::i64) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); @@ -17528,6 +17530,22 @@ static SDValue PerformAndCombine(SDNode *N, SelectionDAG &DAG, if (N1.getOpcode() == ISD::ADD && N1.getOperand(0) == N0 && isAllOnes(N1.getOperand(1))) return DAG.getNode(X86ISD::BLSR, DL, VT, N0); + + // Check for BEXTR + if (N0.getOpcode() == ISD::SRA || N0.getOpcode() == ISD::SRL) { + ConstantSDNode *MaskNode = dyn_cast(N1); + ConstantSDNode *ShiftNode = dyn_cast(N0.getOperand(1)); + if (MaskNode && ShiftNode) { + uint64_t Mask = MaskNode->getZExtValue(); + uint64_t Shift = ShiftNode->getZExtValue(); + if (isMask_64(Mask)) { + uint64_t MaskSize = CountPopulation_64(Mask); + if (Shift + MaskSize <= VT.getSizeInBits()) + return DAG.getNode(X86ISD::BEXTR, DL, VT, N0.getOperand(0), + DAG.getConstant(Shift | (MaskSize << 8), VT)); + } + } + } } if (Subtarget->hasBMI2()) { diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 6a2e4d27905..642df944b0c 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -296,6 +296,7 @@ namespace llvm { BLSMSK, // BLSMSK - Get mask up to lowest set bit BLSR, // BLSR - Reset lowest set bit BZHI, // BZHI - Zero high bits + BEXTR, // BEXTR - Bit field extract UMUL, // LOW, HI, FLAGS = umul LHS, RHS diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 869b9e0dfe3..9aa75ff66ce 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -253,6 +253,7 @@ def X86blsi : SDNode<"X86ISD::BLSI", SDTIntUnaryOp>; def X86blsmsk : SDNode<"X86ISD::BLSMSK", SDTIntUnaryOp>; def X86blsr : SDNode<"X86ISD::BLSR", SDTIntUnaryOp>; def X86bzhi : SDNode<"X86ISD::BZHI", SDTIntShiftOp>; +def X86bextr : SDNode<"X86ISD::BEXTR", SDTIntShiftOp>; def X86mul_imm : SDNode<"X86ISD::MUL_IMM", SDTIntBinOp>; @@ -1869,6 +1870,15 @@ def : Pat<(X86bzhi (loadi64 addr:$src1), GR8:$src2), (BZHI64rm addr:$src1, (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR8:$src2, sub_8bit))>; +def : Pat<(X86bextr GR32:$src1, GR32:$src2), + (BEXTR32rr GR32:$src1, GR32:$src2)>; +def : Pat<(X86bextr (loadi32 addr:$src1), GR32:$src2), + (BEXTR32rm addr:$src1, GR32:$src2)>; +def : Pat<(X86bextr GR64:$src1, GR64:$src2), + (BEXTR64rr GR64:$src1, GR64:$src2)>; +def : Pat<(X86bextr (loadi64 addr:$src1), GR64:$src2), + (BEXTR64rm addr:$src1, GR64:$src2)>; + multiclass bmi_pdep_pext { diff --git a/test/CodeGen/X86/bmi.ll b/test/CodeGen/X86/bmi.ll index 757e98d28d2..242075a878b 100644 --- a/test/CodeGen/X86/bmi.ll +++ b/test/CodeGen/X86/bmi.ll @@ -111,6 +111,23 @@ define i32 @bextr32_load(i32* %x, i32 %y) nounwind readnone { declare i32 @llvm.x86.bmi.bextr.32(i32, i32) nounwind readnone +define i32 @bextr32b(i32 %x) nounwind uwtable readnone ssp { + %1 = lshr i32 %x, 4 + %2 = and i32 %1, 4095 + ret i32 %2 +; CHECK-LABEL: bextr32b: +; CHECK: bextrl +} + +define i32 @bextr32b_load(i32* %x) nounwind uwtable readnone ssp { + %1 = load i32* %x + %2 = lshr i32 %1, 4 + %3 = and i32 %2, 4095 + ret i32 %3 +; CHECK-LABEL: bextr32b_load: +; CHECK: bextrl {{.*}}, ({{.*}}), {{.*}} +} + define i64 @bextr64(i64 %x, i64 %y) nounwind readnone { %tmp = tail call i64 @llvm.x86.bmi.bextr.64(i64 %x, i64 %y) ret i64 %tmp @@ -120,6 +137,14 @@ define i64 @bextr64(i64 %x, i64 %y) nounwind readnone { declare i64 @llvm.x86.bmi.bextr.64(i64, i64) nounwind readnone +define i64 @bextr64b(i64 %x) nounwind uwtable readnone ssp { + %1 = lshr i64 %x, 4 + %2 = and i64 %1, 4095 + ret i64 %2 +; CHECK-LABEL: bextr64b: +; CHECK: bextrq +} + define i32 @bzhi32(i32 %x, i32 %y) nounwind readnone { %tmp = tail call i32 @llvm.x86.bmi.bzhi.32(i32 %x, i32 %y) ret i32 %tmp