diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 1d135ef7bdd1..dbc1ca909a29 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4408,6 +4408,44 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) { return SDValue(); } +// isTruncateOf - If N is a truncate of some other value, return true, record +// the value being truncated in Op and which of Op's bits are zero in KnownZero. +// This function computes KnownZero to avoid a duplicated call to +// ComputeMaskedBits in the caller. +static bool isTruncateOf(SelectionDAG &DAG, SDValue N, SDValue &Op, + APInt &KnownZero) { + APInt KnownOne; + if (N->getOpcode() == ISD::TRUNCATE) { + Op = N->getOperand(0); + DAG.ComputeMaskedBits(Op, KnownZero, KnownOne); + return true; + } + + if (N->getOpcode() != ISD::SETCC || N->getValueType(0) != MVT::i1 || + cast(N->getOperand(2))->get() != ISD::SETNE) + return false; + + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + assert(Op0.getValueType() == Op1.getValueType()); + + ConstantSDNode *COp0 = dyn_cast(Op0); + ConstantSDNode *COp1 = dyn_cast(Op1); + if (COp0 && COp0->getZExtValue() == 0) + Op = Op1; + else if (COp1 && COp1->getZExtValue() == 0) + Op = Op0; + else + return false; + + DAG.ComputeMaskedBits(Op, KnownZero, KnownOne); + + if (!(KnownZero | APInt(Op.getValueSizeInBits(), 1)).isAllOnesValue()) + return false; + + return true; +} + SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { SDValue N0 = N->getOperand(0); EVT VT = N->getValueType(0); @@ -4425,15 +4463,16 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { // (zext (truncate x)) -> (truncate x) // This is valid when the truncated bits of x are already zero. // FIXME: We should extend this to work for vectors too. - if (N0.getOpcode() == ISD::TRUNCATE && !VT.isVector()) { - SDValue Op = N0.getOperand(0); - APInt TruncatedBits - = APInt::getBitsSet(Op.getValueSizeInBits(), - N0.getValueSizeInBits(), - std::min(Op.getValueSizeInBits(), - VT.getSizeInBits())); - APInt KnownZero, KnownOne; - DAG.ComputeMaskedBits(Op, KnownZero, KnownOne); + SDValue Op; + APInt KnownZero; + if (!VT.isVector() && isTruncateOf(DAG, N0, Op, KnownZero)) { + APInt TruncatedBits = + (Op.getValueSizeInBits() == N0.getValueSizeInBits()) ? + APInt(Op.getValueSizeInBits(), 0) : + APInt::getBitsSet(Op.getValueSizeInBits(), + N0.getValueSizeInBits(), + std::min(Op.getValueSizeInBits(), + VT.getSizeInBits())); if (TruncatedBits == (KnownZero & TruncatedBits)) { if (VT.bitsGT(Op.getValueType())) return DAG.getNode(ISD::ZERO_EXTEND, N->getDebugLoc(), VT, Op); diff --git a/llvm/test/CodeGen/X86/pr12360.ll b/llvm/test/CodeGen/X86/pr12360.ll index b57e322b2ce8..f29e50e29a3b 100644 --- a/llvm/test/CodeGen/X86/pr12360.ll +++ b/llvm/test/CodeGen/X86/pr12360.ll @@ -1,14 +1,46 @@ ; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s define zeroext i1 @f1(i8* %x) { +; CHECK: f1: +; CHECK: movb (%rdi), %al +; CHECK-NEXT: ret + entry: %0 = load i8* %x, align 1, !range !0 %tobool = trunc i8 %0 to i1 ret i1 %tobool } -; CHECK: f1: +define zeroext i1 @f2(i8* %x) { +; CHECK: f2: ; CHECK: movb (%rdi), %al ; CHECK-NEXT: ret +entry: + %0 = load i8* %x, align 1, !range !0 + %tobool = icmp ne i8 %0, 0 + ret i1 %tobool +} + !0 = metadata !{i8 0, i8 2} + + +; check that we don't build a "trunc" from i1 to i1, which would assert. +define zeroext i1 @f3(i1 %x) { +; CHECK: f3: + +entry: + %tobool = icmp ne i1 %x, 0 + ret i1 %tobool +} + +; check that we don't build a trunc when other bits are needed +define zeroext i1 @f4(i32 %x) { +; CHECK: f4: +; CHECK: and + +entry: + %y = and i32 %x, 32768 + %z = icmp ne i32 %y, 0 + ret i1 %z +}