diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 73572e92d7a..75b5180a943 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -10750,6 +10750,93 @@ combineElementTruncationToVectorTruncation(SDNode *N, return SDValue(); } +/// \brief Reduce the number of loads when building a vector. +/// +/// Building a vector out of multiple loads can be converted to a load +/// of the vector type if the loads are consecutive. If the loads are +/// consecutive but in descending order, a shuffle is added at the end +/// to reorder the vector. +static SDValue combineBVOfConsecutiveLoads(SDNode *N, SelectionDAG &DAG) { + assert(N->getOpcode() == ISD::BUILD_VECTOR && + "Should be called with a BUILD_VECTOR node"); + + SDLoc dl(N); + bool InputsAreConsecutiveLoads = true; + bool InputsAreReverseConsecutive = true; + unsigned ElemSize = N->getValueType(0).getScalarSizeInBits() / 8; + SDValue FirstInput = N->getOperand(0); + bool IsRoundOfExtLoad = false; + + if (FirstInput.getOpcode() == ISD::FP_ROUND && + FirstInput.getOperand(0).getOpcode() == ISD::LOAD) { + LoadSDNode *LD = dyn_cast(FirstInput.getOperand(0)); + IsRoundOfExtLoad = LD->getExtensionType() == ISD::EXTLOAD; + } + // Not a build vector of (possibly fp_rounded) loads. + if (!IsRoundOfExtLoad && FirstInput.getOpcode() != ISD::LOAD) + return SDValue(); + + for (int i = 1, e = N->getNumOperands(); i < e; ++i) { + // If any inputs are fp_round(extload), they all must be. + if (IsRoundOfExtLoad && N->getOperand(i).getOpcode() != ISD::FP_ROUND) + return SDValue(); + + SDValue NextInput = IsRoundOfExtLoad ? N->getOperand(i).getOperand(0) : + N->getOperand(i); + if (NextInput.getOpcode() != ISD::LOAD) + return SDValue(); + + SDValue PreviousInput = + IsRoundOfExtLoad ? N->getOperand(i-1).getOperand(0) : N->getOperand(i-1); + LoadSDNode *LD1 = dyn_cast(PreviousInput); + LoadSDNode *LD2 = dyn_cast(NextInput); + + // If any inputs are fp_round(extload), they all must be. + if (IsRoundOfExtLoad && LD2->getExtensionType() != ISD::EXTLOAD) + return SDValue(); + + if (!isConsecutiveLS(LD2, LD1, ElemSize, 1, DAG)) + InputsAreConsecutiveLoads = false; + if (!isConsecutiveLS(LD1, LD2, ElemSize, 1, DAG)) + InputsAreReverseConsecutive = false; + + // Exit early if the loads are neither consecutive nor reverse consecutive. + if (!InputsAreConsecutiveLoads && !InputsAreReverseConsecutive) + return SDValue(); + } + + assert(!(InputsAreConsecutiveLoads && InputsAreReverseConsecutive) && + "The loads cannot be both consecutive and reverse consecutive."); + + SDValue FirstLoadOp = + IsRoundOfExtLoad ? FirstInput.getOperand(0) : FirstInput; + SDValue LastLoadOp = + IsRoundOfExtLoad ? N->getOperand(N->getNumOperands()-1).getOperand(0) : + N->getOperand(N->getNumOperands()-1); + + LoadSDNode *LD1 = dyn_cast(FirstLoadOp); + LoadSDNode *LDL = dyn_cast(LastLoadOp); + if (InputsAreConsecutiveLoads) { + assert(LD1 && "Input needs to be a LoadSDNode."); + return DAG.getLoad(N->getValueType(0), dl, LD1->getChain(), + LD1->getBasePtr(), LD1->getPointerInfo(), + LD1->getAlignment()); + } + if (InputsAreReverseConsecutive) { + assert(LDL && "Input needs to be a LoadSDNode."); + SDValue Load = DAG.getLoad(N->getValueType(0), dl, LDL->getChain(), + LDL->getBasePtr(), LDL->getPointerInfo(), + LDL->getAlignment()); + SmallVector Ops; + for (int i = N->getNumOperands() - 1; i >= 0; i--) + Ops.push_back(i); + + return DAG.getVectorShuffle(N->getValueType(0), dl, Load, + DAG.getUNDEF(N->getValueType(0)), Ops); + } + return SDValue(); +} + SDValue PPCTargetLowering::DAGCombineBuildVector(SDNode *N, DAGCombinerInfo &DCI) const { assert(N->getOpcode() == ISD::BUILD_VECTOR && @@ -10770,21 +10857,28 @@ SDValue PPCTargetLowering::DAGCombineBuildVector(SDNode *N, if (Reduced) return Reduced; } + + // If we're building a vector out of consecutive loads, just load that + // vector type. + SDValue Reduced = combineBVOfConsecutiveLoads(N, DAG); + if (Reduced) + return Reduced; + if (N->getValueType(0) != MVT::v2f64) return SDValue(); // Looking for: // (build_vector ([su]int_to_fp (extractelt 0)), [su]int_to_fp (extractelt 1)) - if (N->getOperand(0).getOpcode() != ISD::SINT_TO_FP && - N->getOperand(0).getOpcode() != ISD::UINT_TO_FP) + if (FirstInput.getOpcode() != ISD::SINT_TO_FP && + FirstInput.getOpcode() != ISD::UINT_TO_FP) return SDValue(); if (N->getOperand(1).getOpcode() != ISD::SINT_TO_FP && N->getOperand(1).getOpcode() != ISD::UINT_TO_FP) return SDValue(); - if (N->getOperand(0).getOpcode() != N->getOperand(1).getOpcode()) + if (FirstInput.getOpcode() != N->getOperand(1).getOpcode()) return SDValue(); - SDValue Ext1 = N->getOperand(0).getOperand(0); + SDValue Ext1 = FirstInput.getOperand(0); SDValue Ext2 = N->getOperand(1).getOperand(0); if(Ext1.getOpcode() != ISD::EXTRACT_VECTOR_ELT || Ext2.getOpcode() != ISD::EXTRACT_VECTOR_ELT)