Index: lib/Target/X86/X86ISelDAGToDAG.cpp =================================================================== --- lib/Target/X86/X86ISelDAGToDAG.cpp +++ lib/Target/X86/X86ISelDAGToDAG.cpp @@ -2816,25 +2816,36 @@ SDLoc DL(Node); + // If we do *NOT* have BMI2, let's find out if the if the 'X' is *logically* + // shifted (potentially with trunc inbetween), and if so look past truncation. + MVT XVT = NVT; + if (!Subtarget->hasBMI2() && X.getOpcode() == ISD::TRUNCATE && + X.getOperand(0).getOpcode() == ISD::SRL) { + assert(NVT == MVT::i32 && "Expected target valuetype to be i32"); + X = X.getOperand(0); + XVT = X.getSimpleValueType(); + assert(XVT == MVT::i64 && "Expected truncation from i64"); + } + SDValue OrigNBits = NBits; - if (NBits.getValueType() != NVT) { + if (NBits.getValueType() != XVT) { // Truncate the shift amount. NBits = CurDAG->getNode(ISD::TRUNCATE, DL, MVT::i8, NBits); insertDAGNode(*CurDAG, OrigNBits, NBits); - // Insert 8-bit NBits into lowest 8 bits of NVT-sized (32 or 64-bit) + // Insert 8-bit NBits into lowest 8 bits of XVT-sized (32 or 64-bit) // register. All the other bits are undefined, we do not care about them. SDValue ImplDef = - SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, NVT), 0); + SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, XVT), 0); insertDAGNode(*CurDAG, OrigNBits, ImplDef); NBits = - CurDAG->getTargetInsertSubreg(X86::sub_8bit, DL, NVT, ImplDef, NBits); + CurDAG->getTargetInsertSubreg(X86::sub_8bit, DL, XVT, ImplDef, NBits); insertDAGNode(*CurDAG, OrigNBits, NBits); } if (Subtarget->hasBMI2()) { // Great, just emit the the BZHI.. - SDValue Extract = CurDAG->getNode(X86ISD::BZHI, DL, NVT, X, NBits); + SDValue Extract = CurDAG->getNode(X86ISD::BZHI, DL, XVT, X, NBits); ReplaceNode(Node, Extract.getNode()); SelectCode(Extract.getNode()); return true; @@ -2849,7 +2860,7 @@ // Shift NBits left by 8 bits, thus producing 'control'. // This makes the low 8 bits to be zero. SDValue C8 = CurDAG->getConstant(8, DL, MVT::i8); - SDValue Control = CurDAG->getNode(ISD::SHL, DL, NVT, NBits, C8); + SDValue Control = CurDAG->getNode(ISD::SHL, DL, XVT, NBits, C8); insertDAGNode(*CurDAG, OrigNBits, Control); // If the 'X' is *logically* shifted, we can fold that shift into 'control'. @@ -2862,16 +2873,23 @@ // Now, *zero*-extend the shift amount. The bits 8...15 *must* be zero! SDValue OrigShiftAmt = ShiftAmt; - ShiftAmt = CurDAG->getNode(ISD::ZERO_EXTEND, DL, NVT, ShiftAmt); + ShiftAmt = CurDAG->getNode(ISD::ZERO_EXTEND, DL, XVT, ShiftAmt); insertDAGNode(*CurDAG, OrigShiftAmt, ShiftAmt); // And now 'or' these low 8 bits of shift amount into the 'control'. - Control = CurDAG->getNode(ISD::OR, DL, NVT, Control, ShiftAmt); + Control = CurDAG->getNode(ISD::OR, DL, XVT, Control, ShiftAmt); insertDAGNode(*CurDAG, OrigNBits, Control); } // And finally, form the BEXTR itself. - SDValue Extract = CurDAG->getNode(X86ISD::BEXTR, DL, NVT, X, Control); + SDValue Extract = CurDAG->getNode(X86ISD::BEXTR, DL, XVT, X, Control); + + // The 'X' was originally truncated. Do that now. + if (XVT != NVT) { + insertDAGNode(*CurDAG, OrigNBits, Extract); + Extract = CurDAG->getNode(ISD::TRUNCATE, DL, NVT, Extract); + } + ReplaceNode(Node, Extract.getNode()); SelectCode(Extract.getNode()); Index: test/CodeGen/X86/extract-bits.ll =================================================================== --- test/CodeGen/X86/extract-bits.ll +++ test/CodeGen/X86/extract-bits.ll @@ -1828,11 +1828,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_a1: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_a1: @@ -1929,11 +1930,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_a2: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_a2: @@ -3515,11 +3517,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_b1: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_b1: @@ -3617,11 +3620,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_b2: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_b2: @@ -5986,11 +5990,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_c1: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_c1: @@ -6085,11 +6090,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_c2: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_c2: @@ -7611,11 +7617,12 @@ ; ; X64-BMI1NOTBM-LABEL: bextr64_32_d1: ; X64-BMI1NOTBM: # %bb.0: -; X64-BMI1NOTBM-NEXT: movq %rsi, %rcx -; X64-BMI1NOTBM-NEXT: # kill: def $cl killed $cl killed $rcx -; X64-BMI1NOTBM-NEXT: shrq %cl, %rdi -; X64-BMI1NOTBM-NEXT: shll $8, %edx -; X64-BMI1NOTBM-NEXT: bextrl %edx, %edi, %eax +; X64-BMI1NOTBM-NEXT: # kill: def $edx killed $edx def $rdx +; X64-BMI1NOTBM-NEXT: shlq $8, %rdx +; X64-BMI1NOTBM-NEXT: movzbl %sil, %eax +; X64-BMI1NOTBM-NEXT: orq %rdx, %rax +; X64-BMI1NOTBM-NEXT: bextrq %rax, %rdi, %rax +; X64-BMI1NOTBM-NEXT: # kill: def $eax killed $eax killed $rax ; X64-BMI1NOTBM-NEXT: retq ; ; X64-BMI1BMI2-LABEL: bextr64_32_d1: