Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -24074,13 +24074,59 @@ return SDValue(); } -// PerformXorCombine - Attempts to turn XOR nodes into BLSMSK nodes +// Try to turn tests against the signbit in the form of: +// XOR(TRUNCATE(SRL(X, size(X)-1)), 1) +// into: +// SETGT(X, -1) +static SDValue foldXorTruncShiftIntoCmp(SDNode *N, SelectionDAG &DAG) { + // This is only worth doing if the output type is i8. + if (N->getValueType(0) != MVT::i8) + return SDValue(); + + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + + // We should be performing an xor against a truncated shift. + if (N0.getOpcode() != ISD::TRUNCATE || !N0.hasOneUse()) + return SDValue(); + + // Make sure we are performing an xor against one. + if (!isa(N1) || !cast(N1)->isOne()) + return SDValue(); + + // SetCC on x86 zero extends so only act on this if it's a logical shift. + SDValue Shift = N0.getOperand(0); + if (Shift.getOpcode() != ISD::SRL || !Shift.hasOneUse()) + return SDValue(); + + // Make sure we are truncating from one of i16, i32 or i64. + EVT ShiftTy = Shift.getValueType(); + if (ShiftTy != MVT::i16 && ShiftTy != MVT::i32 && ShiftTy != MVT::i64) + return SDValue(); + + // Make sure the shift amount extracts the sign bit. + if (!isa(Shift.getOperand(1)) || + Shift.getConstantOperandVal(1) != ShiftTy.getSizeInBits() - 1) + return SDValue(); + + // Create a greater-than comparison against -1. + SDLoc DL(N); + SDValue ShiftOp = Shift.getOperand(0); + EVT ShiftOpTy = ShiftOp.getValueType(); + SDValue Cond = DAG.getSetCC(DL, MVT::i8, ShiftOp, + DAG.getConstant(-1, DL, ShiftOpTy), ISD::SETGT); + return Cond; +} + static SDValue PerformXorCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const X86Subtarget *Subtarget) { if (DCI.isBeforeLegalizeOps()) return SDValue(); + if (SDValue RV = foldXorTruncShiftIntoCmp(N, DAG)) + return RV; + if (Subtarget->hasCMov()) if (SDValue RV = performIntegerAbsCombine(N, DAG)) return RV; Index: test/CodeGen/X86/cmp.ll =================================================================== --- test/CodeGen/X86/cmp.ll +++ test/CodeGen/X86/cmp.ll @@ -211,3 +211,47 @@ ; CHECK: shrl $16, %edi ; CHECK: cmpl %esi, %edi } + +define i8 @test16(i16 signext %L) { + %lshr = lshr i16 %L, 15 + %trunc = trunc i16 %lshr to i8 + %not = xor i8 %trunc, 1 + ret i8 %not + +; CHECK-LABEL: test16: +; CHECK: testw %di, %di +; CHECK: setns %al +} + +define i8 @test17(i32 %L) { + %lshr = lshr i32 %L, 31 + %trunc = trunc i32 %lshr to i8 + %not = xor i8 %trunc, 1 + ret i8 %not + +; CHECK-LABEL: test17: +; CHECK: testl %edi, %edi +; CHECK: setns %al +} + +define i8 @test18(i64 %L) { + %lshr = lshr i64 %L, 63 + %trunc = trunc i64 %lshr to i8 + %not = xor i8 %trunc, 1 + ret i8 %not + +; CHECK-LABEL: test18: +; CHECK: testq %rdi, %rdi +; CHECK: setns %al +} + +define zeroext i1 @test19(i32 %L) { + %lshr = lshr i32 %L, 31 + %trunc = trunc i32 %lshr to i1 + %not = xor i1 %trunc, 1 + ret i1 %not + +; CHECK-LABEL: test19: +; CHECK: testl %edi, %edi +; CHECK: setns %al +}