From: Chris Lattner Date: Wed, 19 Jan 2005 04:19:40 +0000 (+0000) Subject: Implement a way of expanding shifts. This applies to targets that offer X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e34b396ab7d28469bf3d9679a748b643d8e30458;p=oota-llvm.git Implement a way of expanding shifts. This applies to targets that offer select operations or to shifts that are by a constant. This automatically implements (with no special code) all of the special cases for shift by 32, shift by < 32 and shift by > 32. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19679 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 52e723a57e5..b560acb5053 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -119,6 +119,9 @@ private: void ExpandOp(SDOperand O, SDOperand &Lo, SDOperand &Hi); SDOperand PromoteOp(SDOperand O); + bool ExpandShift(unsigned Opc, SDOperand Op, SDOperand Amt, + SDOperand &Lo, SDOperand &Hi); + SDOperand getIntPtrConstant(uint64_t Val) { return DAG.getConstant(Val, TLI.getPointerTy()); } @@ -1157,6 +1160,71 @@ SDOperand SelectionDAGLegalize::PromoteOp(SDOperand Op) { return Result; } +/// ExpandShift - Try to find a clever way to expand this shift operation out to +/// smaller elements. If we can't find a way that is more efficient than a +/// libcall on this target, return false. Otherwise, return true with the +/// low-parts expanded into Lo and Hi. +bool SelectionDAGLegalize::ExpandShift(unsigned Opc, SDOperand Op,SDOperand Amt, + SDOperand &Lo, SDOperand &Hi) { + assert((Opc == ISD::SHL || Opc == ISD::SRA || Opc == ISD::SRL) && + "This is not a shift!"); + MVT::ValueType NVT = TLI.getTypeToTransformTo(Op.getValueType()); + + // If we have an efficient select operation (or if the selects will all fold + // away), lower to some complex code, otherwise just emit the libcall. + if (TLI.getOperationAction(ISD::SELECT, NVT) != TargetLowering::Legal && + !isa(Amt)) + return false; + + SDOperand InL, InH; + ExpandOp(Op, InL, InH); + SDOperand ShAmt = LegalizeOp(Amt); + SDOperand OShAmt = ShAmt; // Unmasked shift amount. + MVT::ValueType ShTy = ShAmt.getValueType(); + + unsigned NVTBits = MVT::getSizeInBits(NVT); + SDOperand NAmt = DAG.getNode(ISD::SUB, ShTy, // NAmt = 32-ShAmt + DAG.getConstant(NVTBits, ShTy), ShAmt); + + if (TLI.getShiftAmountFlavor() != TargetLowering::Mask) { + ShAmt = DAG.getNode(ISD::AND, ShTy, ShAmt, // ShAmt &= 31 + DAG.getConstant(NVTBits-1, ShTy)); + NAmt = DAG.getNode(ISD::AND, ShTy, NAmt, // NAmt &= 31 + DAG.getConstant(NVTBits-1, ShTy)); + } + + if (Opc == ISD::SHL) { + SDOperand T1 = DAG.getNode(ISD::OR, NVT,// T1 = (Hi << Amt) | (Lo >> NAmt) + DAG.getNode(ISD::SHL, NVT, InH, ShAmt), + DAG.getNode(ISD::SRL, NVT, InL, NAmt)); + SDOperand T2 = DAG.getNode(ISD::SHL, NVT, InL, ShAmt); // T2 = Lo << Amt + + SDOperand Cond = DAG.getSetCC(ISD::SETGE, TLI.getSetCCResultTy(), OShAmt, + DAG.getConstant(NVTBits, ShTy)); + Hi = DAG.getNode(ISD::SELECT, NVT, Cond, T2, T1); + Lo = DAG.getNode(ISD::SELECT, NVT, Cond, DAG.getConstant(0, NVT), T2); + } else { + SDOperand T1 = DAG.getNode(ISD::OR, NVT,// T1 = (Hi << NAmt) | (Lo >> Amt) + DAG.getNode(ISD::SHL, NVT, InH, NAmt), + DAG.getNode(ISD::SRL, NVT, InL, ShAmt)); + bool isSign = Opc == ISD::SRA; + SDOperand T2 = DAG.getNode(Opc, NVT, InH, ShAmt); + + SDOperand HiPart; + if (isSign) + HiPart = DAG.getNode(Opc, NVT, InH, DAG.getConstant(NVTBits-1, ShTy)); + else + HiPart = DAG.getConstant(0, NVT); + SDOperand Cond = DAG.getSetCC(ISD::SETGE, TLI.getSetCCResultTy(), OShAmt, + DAG.getConstant(NVTBits, ShTy)); + Lo = DAG.getNode(ISD::SELECT, NVT, Cond, T2, T1); + Hi = DAG.getNode(ISD::SELECT, NVT, Cond, HiPart,T2); + } + return true; +} + + + /// ExpandOp - Expand the specified SDOperand into its two component pieces /// Lo&Hi. Note that the Op MUST be an expanded type. As a result of this, the /// LegalizeNodes map is filled in for any results that are not expanded, the @@ -1316,6 +1384,32 @@ void SelectionDAGLegalize::ExpandOp(SDOperand Op, SDOperand &Lo, SDOperand &Hi){ LibCallName = "__fixunsdfdi"; break; + case ISD::SHL: + // If we can emit an efficient shift operation, do so now. + if (ExpandShift(ISD::SHL, Node->getOperand(0), Node->getOperand(1), + Lo, Hi)) + break; + // Otherwise, emit a libcall. + LibCallName = "__ashldi3"; + break; + + case ISD::SRA: + // If we can emit an efficient shift operation, do so now. + if (ExpandShift(ISD::SRA, Node->getOperand(0), Node->getOperand(1), + Lo, Hi)) + break; + // Otherwise, emit a libcall. + LibCallName = "__ashrdi3"; + break; + case ISD::SRL: + // If we can emit an efficient shift operation, do so now. + if (ExpandShift(ISD::SRL, Node->getOperand(0), Node->getOperand(1), + Lo, Hi)) + break; + // Otherwise, emit a libcall. + LibCallName = "__lshrdi3"; + break; + case ISD::ADD: LibCallName = "__adddi3"; break; case ISD::SUB: LibCallName = "__subdi3"; break; case ISD::MUL: LibCallName = "__muldi3"; break; @@ -1323,9 +1417,6 @@ void SelectionDAGLegalize::ExpandOp(SDOperand Op, SDOperand &Lo, SDOperand &Hi){ case ISD::UDIV: LibCallName = "__udivdi3"; break; case ISD::SREM: LibCallName = "__moddi3"; break; case ISD::UREM: LibCallName = "__umoddi3"; break; - case ISD::SHL: LibCallName = "__ashldi3"; break; - case ISD::SRA: LibCallName = "__ashrdi3"; break; - case ISD::SRL: LibCallName = "__lshrdi3"; break; } // Int2FP -> __floatdisf/__floatdidf