diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index d10e63c66b7..4f58c5f5f05 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -290,6 +290,15 @@ public: /// isMaskedValueZeroForTargetNode method, to allow target nodes to be /// understood. bool MaskedValueIsZero(const SDOperand &Op, uint64_t Mask) const; + + /// DemandedBitsAreZero - Return true if 'Op & Mask' demands no bits from a + /// bit set operation such as a sign extend or or/xor with constant whose only + /// use is Op. If it returns true, the old node that sets bits which are + /// not demanded is returned in Old, and its replacement node is returned in + /// New, such that callers of SetBitsAreZero may call CombineTo on them if + /// desired. + bool DemandedBitsAreZero(const SDOperand &Op, uint64_t Mask, SDOperand &Old, + SDOperand &New, SelectionDAG &DAG); //===--------------------------------------------------------------------===// // TargetLowering Configuration Methods - These methods should be invoked by diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 3124da575aa..8287f2d0965 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -858,7 +858,7 @@ SDOperand DAGCombiner::visitMULHU(SDNode *N) { SDOperand DAGCombiner::visitAND(SDNode *N) { SDOperand N0 = N->getOperand(0); SDOperand N1 = N->getOperand(1); - SDOperand LL, LR, RL, RR, CC0, CC1; + SDOperand LL, LR, RL, RR, CC0, CC1, Old, New; ConstantSDNode *N0C = dyn_cast(N0); ConstantSDNode *N1C = dyn_cast(N1); MVT::ValueType VT = N1.getValueType(); @@ -884,13 +884,6 @@ SDOperand DAGCombiner::visitAND(SDNode *N) { SDOperand RAND = ReassociateOps(ISD::AND, N0, N1); if (RAND.Val != 0) return RAND; - // fold (and (sign_extend_inreg x, i16 to i32), 1) -> (and x, 1) - if (N1C && N0.getOpcode() == ISD::SIGN_EXTEND_INREG) { - unsigned ExtendBits = - MVT::getSizeInBits(cast(N0.getOperand(1))->getVT()); - if (ExtendBits == 64 || ((N1C->getValue() & (~0ULL << ExtendBits)) == 0)) - return DAG.getNode(ISD::AND, VT, N0.getOperand(0), N1); - } // fold (and (or x, 0xFFFF), 0xFF) -> 0xFF if (N1C && N0.getOpcode() == ISD::OR) if (ConstantSDNode *ORI = dyn_cast(N0.getOperand(1))) @@ -966,6 +959,26 @@ SDOperand DAGCombiner::visitAND(SDNode *N) { WorkList.push_back(ANDNode.Val); return DAG.getNode(N0.getOpcode(), VT, ANDNode, N0.getOperand(1)); } + // fold (and (sign_extend_inreg x, i16 to i32), 1) -> (and x, 1) + // fold (and (sra)) -> (and (srl)) when possible. + if (TLI.DemandedBitsAreZero(SDOperand(N, 0), ~0ULL >> (64-OpSizeInBits), Old, + New, DAG)) { + WorkList.push_back(N); + CombineTo(Old.Val, New); + return SDOperand(); + } + // FIXME: DemandedBitsAreZero cannot currently handle AND with non-constant + // RHS and propagate known cleared bits to LHS. For this reason, we must keep + // this fold, for now, for the following testcase: + // + //int %test2(uint %mode.0.i.0) { + // %tmp.79 = cast uint %mode.0.i.0 to int + // %tmp.80 = shr int %tmp.79, ubyte 15 + // %tmp.81 = shr uint %mode.0.i.0, ubyte 16 + // %tmp.82 = cast uint %tmp.81 to int + // %tmp.83 = and int %tmp.80, %tmp.82 + // ret int %tmp.83 + //} // fold (and (sra)) -> (and (srl)) when possible. if (N0.getOpcode() == ISD::SRA && N0.Val->hasOneUse()) { if (ConstantSDNode *N01C = dyn_cast(N0.getOperand(1))) { @@ -1240,6 +1253,8 @@ SDOperand DAGCombiner::visitXOR(SDNode *N) { SDOperand DAGCombiner::visitSHL(SDNode *N) { SDOperand N0 = N->getOperand(0); SDOperand N1 = N->getOperand(1); + SDOperand Old = SDOperand(); + SDOperand New = SDOperand(); ConstantSDNode *N0C = dyn_cast(N0); ConstantSDNode *N1C = dyn_cast(N1); MVT::ValueType VT = N0.getValueType(); @@ -1260,6 +1275,12 @@ SDOperand DAGCombiner::visitSHL(SDNode *N) { // if (shl x, c) is known to be zero, return 0 if (N1C && TLI.MaskedValueIsZero(SDOperand(N, 0), ~0ULL >> (64-OpSizeInBits))) return DAG.getConstant(0, VT); + if (N1C && TLI.DemandedBitsAreZero(SDOperand(N,0), ~0ULL >> (64-OpSizeInBits), + Old, New, DAG)) { + WorkList.push_back(N); + CombineTo(Old.Val, New); + return SDOperand(); + } // fold (shl (shl x, c1), c2) -> 0 or (shl x, c1+c2) if (N1C && N0.getOpcode() == ISD::SHL && N0.getOperand(1).getOpcode() == ISD::Constant) { @@ -1650,8 +1671,7 @@ SDOperand DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) { return N0; // fold (sext_in_reg x) -> (zext_in_reg x) if the sign bit is zero if (TLI.MaskedValueIsZero(N0, 1ULL << (EVTBits-1))) - return DAG.getNode(ISD::AND, N0.getValueType(), N0, - DAG.getConstant(~0ULL >> (64-EVTBits), VT)); + return DAG.getZeroExtendInReg(N0, EVT); // fold (sext_in_reg (srl x)) -> sra x if (N0.getOpcode() == ISD::SRL && N0.getOperand(1).getOpcode() == ISD::Constant && diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index c79045b8859..8951490fb6e 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -131,7 +131,63 @@ const char *TargetLowering::getTargetNodeName(unsigned Opcode) const { return NULL; } - +/// DemandedBitsAreZero - Return true if 'Op & Mask' demands no bits from a bit +/// set operation such as a sign extend or or/xor with constant whose only +/// use is Op. If it returns true, the old node that sets bits which are +/// not demanded is returned in Old, and its replacement node is returned in +/// New, such that callers of SetBitsAreZero may call CombineTo on them if +/// desired. +bool TargetLowering::DemandedBitsAreZero(const SDOperand &Op, uint64_t Mask, + SDOperand &Old, SDOperand &New, + SelectionDAG &DAG) { + // If the operation has more than one use, we're not interested in it. + // Tracking down and checking all uses would be problematic and slow. + if (!Op.hasOneUse()) + return false; + + switch (Op.getOpcode()) { + case ISD::AND: + // (X & C1) & C2 == 0 iff C1 & C2 == 0. + if (ConstantSDNode *AndRHS = dyn_cast(Op.getOperand(1))) { + uint64_t NewVal = Mask & AndRHS->getValue(); + return DemandedBitsAreZero(Op.getOperand(0), NewVal, Old, New, DAG); + } + break; + case ISD::SHL: + // (ushl X, C1) & C2 == 0 iff X & (C2 >> C1) == 0 + if (ConstantSDNode *ShAmt = dyn_cast(Op.getOperand(1))) { + uint64_t NewVal = Mask >> ShAmt->getValue(); + return DemandedBitsAreZero(Op.getOperand(0), NewVal, Old, New, DAG); + } + break; + case ISD::SIGN_EXTEND_INREG: { + MVT::ValueType EVT = cast(Op.getOperand(1))->getVT(); + unsigned ExtendBits = MVT::getSizeInBits(EVT); + // If we're extending from something smaller than MVT::i64 and all of the + // sign extension bits are masked, return true and set New to be a zero + // extend inreg from the same type. + if (ExtendBits < 64 && ((Mask & (~0ULL << ExtendBits)) == 0)) { + Old = Op; + New = DAG.getZeroExtendInReg(Op.getOperand(0), EVT); + return true; + } + break; + } + case ISD::SRA: + if (ConstantSDNode *ShAmt = dyn_cast(Op.getOperand(1))) { + unsigned OpBits = MVT::getSizeInBits(Op.getValueType()); + unsigned SH = ShAmt->getValue(); + if (SH && ((Mask & (~0ULL << (OpBits-SH))) == 0)) { + Old = Op; + New = DAG.getNode(ISD::SRL, Op.getValueType(), Op.getOperand(0), + Op.getOperand(1)); + return true; + } + } + break; + } + return false; +} /// MaskedValueIsZero - Return true if 'Op & Mask' is known to be zero. We use /// this predicate to simplify operations downstream. Op and Mask are known to