diff options
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp')
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp | 1020 |
1 files changed, 575 insertions, 445 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp index 15c3a0b6cfad..7d0b1ee6ae07 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp @@ -75,95 +75,95 @@ class VectorLegalizer { SDValue LegalizeOp(SDValue Op); /// Assuming the node is legal, "legalize" the results. - SDValue TranslateLegalizeResults(SDValue Op, SDValue Result); + SDValue TranslateLegalizeResults(SDValue Op, SDNode *Result); + + /// Make sure Results are legal and update the translation cache. + SDValue RecursivelyLegalizeResults(SDValue Op, + MutableArrayRef<SDValue> Results); + + /// Wrapper to interface LowerOperation with a vector of Results. + /// Returns false if the target wants to use default expansion. Otherwise + /// returns true. If return is true and the Results are empty, then the + /// target wants to keep the input node as is. + bool LowerOperationWrapper(SDNode *N, SmallVectorImpl<SDValue> &Results); /// Implements unrolling a VSETCC. - SDValue UnrollVSETCC(SDValue Op); + SDValue UnrollVSETCC(SDNode *Node); /// Implement expand-based legalization of vector operations. /// /// This is just a high-level routine to dispatch to specific code paths for /// operations to legalize them. - SDValue Expand(SDValue Op); + void Expand(SDNode *Node, SmallVectorImpl<SDValue> &Results); /// Implements expansion for FP_TO_UINT; falls back to UnrollVectorOp if /// FP_TO_SINT isn't legal. - SDValue ExpandFP_TO_UINT(SDValue Op); + void ExpandFP_TO_UINT(SDNode *Node, SmallVectorImpl<SDValue> &Results); /// Implements expansion for UINT_TO_FLOAT; falls back to UnrollVectorOp if /// SINT_TO_FLOAT and SHR on vectors isn't legal. - SDValue ExpandUINT_TO_FLOAT(SDValue Op); + void ExpandUINT_TO_FLOAT(SDNode *Node, SmallVectorImpl<SDValue> &Results); /// Implement expansion for SIGN_EXTEND_INREG using SRL and SRA. - SDValue ExpandSEXTINREG(SDValue Op); + SDValue ExpandSEXTINREG(SDNode *Node); /// Implement expansion for ANY_EXTEND_VECTOR_INREG. /// /// Shuffles the low lanes of the operand into place and bitcasts to the proper /// type. The contents of the bits in the extended part of each element are /// undef. - SDValue ExpandANY_EXTEND_VECTOR_INREG(SDValue Op); + SDValue ExpandANY_EXTEND_VECTOR_INREG(SDNode *Node); /// Implement expansion for SIGN_EXTEND_VECTOR_INREG. /// /// Shuffles the low lanes of the operand into place, bitcasts to the proper /// type, then shifts left and arithmetic shifts right to introduce a sign /// extension. - SDValue ExpandSIGN_EXTEND_VECTOR_INREG(SDValue Op); + SDValue ExpandSIGN_EXTEND_VECTOR_INREG(SDNode *Node); /// Implement expansion for ZERO_EXTEND_VECTOR_INREG. /// /// Shuffles the low lanes of the operand into place and blends zeros into /// the remaining lanes, finally bitcasting to the proper type. - SDValue ExpandZERO_EXTEND_VECTOR_INREG(SDValue Op); - - /// Implement expand-based legalization of ABS vector operations. - /// If following expanding is legal/custom then do it: - /// (ABS x) --> (XOR (ADD x, (SRA x, sizeof(x)-1)), (SRA x, sizeof(x)-1)) - /// else unroll the operation. - SDValue ExpandABS(SDValue Op); + SDValue ExpandZERO_EXTEND_VECTOR_INREG(SDNode *Node); /// Expand bswap of vectors into a shuffle if legal. - SDValue ExpandBSWAP(SDValue Op); + SDValue ExpandBSWAP(SDNode *Node); /// Implement vselect in terms of XOR, AND, OR when blend is not /// supported by the target. - SDValue ExpandVSELECT(SDValue Op); - SDValue ExpandSELECT(SDValue Op); - SDValue ExpandLoad(SDValue Op); - SDValue ExpandStore(SDValue Op); - SDValue ExpandFNEG(SDValue Op); - SDValue ExpandFSUB(SDValue Op); - SDValue ExpandBITREVERSE(SDValue Op); - SDValue ExpandCTPOP(SDValue Op); - SDValue ExpandCTLZ(SDValue Op); - SDValue ExpandCTTZ(SDValue Op); - SDValue ExpandFunnelShift(SDValue Op); - SDValue ExpandROT(SDValue Op); - SDValue ExpandFMINNUM_FMAXNUM(SDValue Op); - SDValue ExpandUADDSUBO(SDValue Op); - SDValue ExpandSADDSUBO(SDValue Op); - SDValue ExpandMULO(SDValue Op); - SDValue ExpandAddSubSat(SDValue Op); - SDValue ExpandFixedPointMul(SDValue Op); - SDValue ExpandStrictFPOp(SDValue Op); + SDValue ExpandVSELECT(SDNode *Node); + SDValue ExpandSELECT(SDNode *Node); + std::pair<SDValue, SDValue> ExpandLoad(SDNode *N); + SDValue ExpandStore(SDNode *N); + SDValue ExpandFNEG(SDNode *Node); + void ExpandFSUB(SDNode *Node, SmallVectorImpl<SDValue> &Results); + void ExpandBITREVERSE(SDNode *Node, SmallVectorImpl<SDValue> &Results); + void ExpandUADDSUBO(SDNode *Node, SmallVectorImpl<SDValue> &Results); + void ExpandSADDSUBO(SDNode *Node, SmallVectorImpl<SDValue> &Results); + void ExpandMULO(SDNode *Node, SmallVectorImpl<SDValue> &Results); + SDValue ExpandFixedPointDiv(SDNode *Node); + SDValue ExpandStrictFPOp(SDNode *Node); + void ExpandStrictFPOp(SDNode *Node, SmallVectorImpl<SDValue> &Results); + + void UnrollStrictFPOp(SDNode *Node, SmallVectorImpl<SDValue> &Results); /// Implements vector promotion. /// /// This is essentially just bitcasting the operands to a different type and /// bitcasting the result back to the original type. - SDValue Promote(SDValue Op); + void Promote(SDNode *Node, SmallVectorImpl<SDValue> &Results); /// Implements [SU]INT_TO_FP vector promotion. /// /// This is a [zs]ext of the input operand to a larger integer type. - SDValue PromoteINT_TO_FP(SDValue Op); + void PromoteINT_TO_FP(SDNode *Node, SmallVectorImpl<SDValue> &Results); /// Implements FP_TO_[SU]INT vector promotion of the result type. /// /// It is promoted to a larger integer type. The result is then /// truncated back to the original type. - SDValue PromoteFP_TO_INT(SDValue Op); + void PromoteFP_TO_INT(SDNode *Node, SmallVectorImpl<SDValue> &Results); public: VectorLegalizer(SelectionDAG& dag) : @@ -219,11 +219,27 @@ bool VectorLegalizer::Run() { return Changed; } -SDValue VectorLegalizer::TranslateLegalizeResults(SDValue Op, SDValue Result) { +SDValue VectorLegalizer::TranslateLegalizeResults(SDValue Op, SDNode *Result) { + assert(Op->getNumValues() == Result->getNumValues() && + "Unexpected number of results"); // Generic legalization: just pass the operand through. - for (unsigned i = 0, e = Op.getNode()->getNumValues(); i != e; ++i) - AddLegalizedOperand(Op.getValue(i), Result.getValue(i)); - return Result.getValue(Op.getResNo()); + for (unsigned i = 0, e = Op->getNumValues(); i != e; ++i) + AddLegalizedOperand(Op.getValue(i), SDValue(Result, i)); + return SDValue(Result, Op.getResNo()); +} + +SDValue +VectorLegalizer::RecursivelyLegalizeResults(SDValue Op, + MutableArrayRef<SDValue> Results) { + assert(Results.size() == Op->getNumValues() && + "Unexpected number of results"); + // Make sure that the generated code is itself legal. + for (unsigned i = 0, e = Results.size(); i != e; ++i) { + Results[i] = LegalizeOp(Results[i]); + AddLegalizedOperand(Op.getValue(i), Results[i]); + } + + return Results[Op.getResNo()]; } SDValue VectorLegalizer::LegalizeOp(SDValue Op) { @@ -232,18 +248,15 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { DenseMap<SDValue, SDValue>::iterator I = LegalizedNodes.find(Op); if (I != LegalizedNodes.end()) return I->second; - SDNode* Node = Op.getNode(); - // Legalize the operands SmallVector<SDValue, 8> Ops; - for (const SDValue &Op : Node->op_values()) - Ops.push_back(LegalizeOp(Op)); + for (const SDValue &Oper : Op->op_values()) + Ops.push_back(LegalizeOp(Oper)); - SDValue Result = SDValue(DAG.UpdateNodeOperands(Op.getNode(), Ops), - Op.getResNo()); + SDNode *Node = DAG.UpdateNodeOperands(Op.getNode(), Ops); if (Op.getOpcode() == ISD::LOAD) { - LoadSDNode *LD = cast<LoadSDNode>(Op.getNode()); + LoadSDNode *LD = cast<LoadSDNode>(Node); ISD::LoadExtType ExtType = LD->getExtensionType(); if (LD->getMemoryVT().isVector() && ExtType != ISD::NON_EXTLOAD) { LLVM_DEBUG(dbgs() << "\nLegalizing extending vector load: "; @@ -252,26 +265,29 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { LD->getMemoryVT())) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: - return TranslateLegalizeResults(Op, Result); - case TargetLowering::Custom: - if (SDValue Lowered = TLI.LowerOperation(Result, DAG)) { - assert(Lowered->getNumValues() == Op->getNumValues() && - "Unexpected number of results"); - if (Lowered != Result) { - // Make sure the new code is also legal. - Lowered = LegalizeOp(Lowered); - Changed = true; - } - return TranslateLegalizeResults(Op, Lowered); + return TranslateLegalizeResults(Op, Node); + case TargetLowering::Custom: { + SmallVector<SDValue, 2> ResultVals; + if (LowerOperationWrapper(Node, ResultVals)) { + if (ResultVals.empty()) + return TranslateLegalizeResults(Op, Node); + + Changed = true; + return RecursivelyLegalizeResults(Op, ResultVals); } LLVM_FALLTHROUGH; - case TargetLowering::Expand: + } + case TargetLowering::Expand: { Changed = true; - return ExpandLoad(Op); + std::pair<SDValue, SDValue> Tmp = ExpandLoad(Node); + AddLegalizedOperand(Op.getValue(0), Tmp.first); + AddLegalizedOperand(Op.getValue(1), Tmp.second); + return Op.getResNo() ? Tmp.first : Tmp.second; + } } } } else if (Op.getOpcode() == ISD::STORE) { - StoreSDNode *ST = cast<StoreSDNode>(Op.getNode()); + StoreSDNode *ST = cast<StoreSDNode>(Node); EVT StVT = ST->getMemoryVT(); MVT ValVT = ST->getValue().getSimpleValueType(); if (StVT.isVector() && ST->isTruncatingStore()) { @@ -280,19 +296,24 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { switch (TLI.getTruncStoreAction(ValVT, StVT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: - return TranslateLegalizeResults(Op, Result); + return TranslateLegalizeResults(Op, Node); case TargetLowering::Custom: { - SDValue Lowered = TLI.LowerOperation(Result, DAG); - if (Lowered != Result) { - // Make sure the new code is also legal. - Lowered = LegalizeOp(Lowered); + SmallVector<SDValue, 1> ResultVals; + if (LowerOperationWrapper(Node, ResultVals)) { + if (ResultVals.empty()) + return TranslateLegalizeResults(Op, Node); + Changed = true; + return RecursivelyLegalizeResults(Op, ResultVals); } - return TranslateLegalizeResults(Op, Lowered); + LLVM_FALLTHROUGH; } - case TargetLowering::Expand: + case TargetLowering::Expand: { Changed = true; - return ExpandStore(Op); + SDValue Chain = ExpandStore(Node); + AddLegalizedOperand(Op, Chain); + return Chain; + } } } } @@ -300,55 +321,41 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { bool HasVectorValueOrOp = false; for (auto J = Node->value_begin(), E = Node->value_end(); J != E; ++J) HasVectorValueOrOp |= J->isVector(); - for (const SDValue &Op : Node->op_values()) - HasVectorValueOrOp |= Op.getValueType().isVector(); + for (const SDValue &Oper : Node->op_values()) + HasVectorValueOrOp |= Oper.getValueType().isVector(); if (!HasVectorValueOrOp) - return TranslateLegalizeResults(Op, Result); + return TranslateLegalizeResults(Op, Node); TargetLowering::LegalizeAction Action = TargetLowering::Legal; + EVT ValVT; switch (Op.getOpcode()) { default: - return TranslateLegalizeResults(Op, Result); - case ISD::STRICT_FADD: - case ISD::STRICT_FSUB: - case ISD::STRICT_FMUL: - case ISD::STRICT_FDIV: - case ISD::STRICT_FREM: - case ISD::STRICT_FSQRT: - case ISD::STRICT_FMA: - case ISD::STRICT_FPOW: - case ISD::STRICT_FPOWI: - case ISD::STRICT_FSIN: - case ISD::STRICT_FCOS: - case ISD::STRICT_FEXP: - case ISD::STRICT_FEXP2: - case ISD::STRICT_FLOG: - case ISD::STRICT_FLOG10: - case ISD::STRICT_FLOG2: - case ISD::STRICT_FRINT: - case ISD::STRICT_FNEARBYINT: - case ISD::STRICT_FMAXNUM: - case ISD::STRICT_FMINNUM: - case ISD::STRICT_FCEIL: - case ISD::STRICT_FFLOOR: - case ISD::STRICT_FROUND: - case ISD::STRICT_FTRUNC: - case ISD::STRICT_FP_TO_SINT: - case ISD::STRICT_FP_TO_UINT: - case ISD::STRICT_FP_ROUND: - case ISD::STRICT_FP_EXTEND: + return TranslateLegalizeResults(Op, Node); + case ISD::MERGE_VALUES: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); + // This operation lies about being legal: when it claims to be legal, + // it should actually be expanded. + if (Action == TargetLowering::Legal) + Action = TargetLowering::Expand; + break; +#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \ + case ISD::STRICT_##DAGN: +#include "llvm/IR/ConstrainedOps.def" + ValVT = Node->getValueType(0); + if (Op.getOpcode() == ISD::STRICT_SINT_TO_FP || + Op.getOpcode() == ISD::STRICT_UINT_TO_FP) + ValVT = Node->getOperand(1).getValueType(); + Action = TLI.getOperationAction(Node->getOpcode(), ValVT); // If we're asked to expand a strict vector floating-point operation, // by default we're going to simply unroll it. That is usually the // best approach, except in the case where the resulting strict (scalar) // operations would themselves use the fallback mutation to non-strict. // In that specific case, just do the fallback on the vector op. - if (Action == TargetLowering::Expand && - TLI.getStrictFPOperationAction(Node->getOpcode(), - Node->getValueType(0)) - == TargetLowering::Legal) { - EVT EltVT = Node->getValueType(0).getVectorElementType(); + if (Action == TargetLowering::Expand && !TLI.isStrictFPEnabled() && + TLI.getStrictFPOperationAction(Node->getOpcode(), ValVT) == + TargetLowering::Legal) { + EVT EltVT = ValVT.getVectorElementType(); if (TLI.getOperationAction(Node->getOpcode(), EltVT) == TargetLowering::Expand && TLI.getStrictFPOperationAction(Node->getOpcode(), EltVT) @@ -454,7 +461,9 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { case ISD::SMULFIX: case ISD::SMULFIXSAT: case ISD::UMULFIX: - case ISD::UMULFIXSAT: { + case ISD::UMULFIXSAT: + case ISD::SDIVFIX: + case ISD::UDIVFIX: { unsigned Scale = Node->getConstantOperandVal(2); Action = TLI.getFixedPointOperationAction(Node->getOpcode(), Node->getValueType(0), Scale); @@ -482,53 +491,90 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { LLVM_DEBUG(dbgs() << "\nLegalizing vector op: "; Node->dump(&DAG)); + SmallVector<SDValue, 8> ResultVals; switch (Action) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Promote: - Result = Promote(Op); - Changed = true; + LLVM_DEBUG(dbgs() << "Promoting\n"); + Promote(Node, ResultVals); + assert(!ResultVals.empty() && "No results for promotion?"); break; case TargetLowering::Legal: LLVM_DEBUG(dbgs() << "Legal node: nothing to do\n"); break; - case TargetLowering::Custom: { + case TargetLowering::Custom: LLVM_DEBUG(dbgs() << "Trying custom legalization\n"); - if (SDValue Tmp1 = TLI.LowerOperation(Op, DAG)) { - LLVM_DEBUG(dbgs() << "Successfully custom legalized node\n"); - Result = Tmp1; + if (LowerOperationWrapper(Node, ResultVals)) break; - } LLVM_DEBUG(dbgs() << "Could not custom legalize node\n"); LLVM_FALLTHROUGH; - } case TargetLowering::Expand: - Result = Expand(Op); + LLVM_DEBUG(dbgs() << "Expanding\n"); + Expand(Node, ResultVals); + break; } - // Make sure that the generated code is itself legal. - if (Result != Op) { - Result = LegalizeOp(Result); - Changed = true; + if (ResultVals.empty()) + return TranslateLegalizeResults(Op, Node); + + Changed = true; + return RecursivelyLegalizeResults(Op, ResultVals); +} + +// FIME: This is very similar to the X86 override of +// TargetLowering::LowerOperationWrapper. Can we merge them somehow? +bool VectorLegalizer::LowerOperationWrapper(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { + SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); + + if (!Res.getNode()) + return false; + + if (Res == SDValue(Node, 0)) + return true; + + // If the original node has one result, take the return value from + // LowerOperation as is. It might not be result number 0. + if (Node->getNumValues() == 1) { + Results.push_back(Res); + return true; } - // Note that LegalizeOp may be reentered even from single-use nodes, which - // means that we always must cache transformed nodes. - AddLegalizedOperand(Op, Result); - return Result; + // If the original node has multiple results, then the return node should + // have the same number of results. + assert((Node->getNumValues() == Res->getNumValues()) && + "Lowering returned the wrong number of results!"); + + // Places new result values base on N result number. + for (unsigned I = 0, E = Node->getNumValues(); I != E; ++I) + Results.push_back(Res.getValue(I)); + + return true; } -SDValue VectorLegalizer::Promote(SDValue Op) { +void VectorLegalizer::Promote(SDNode *Node, SmallVectorImpl<SDValue> &Results) { // For a few operations there is a specific concept for promotion based on // the operand's type. - switch (Op.getOpcode()) { + switch (Node->getOpcode()) { case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: + case ISD::STRICT_SINT_TO_FP: + case ISD::STRICT_UINT_TO_FP: // "Promote" the operation by extending the operand. - return PromoteINT_TO_FP(Op); + PromoteINT_TO_FP(Node, Results); + return; case ISD::FP_TO_UINT: case ISD::FP_TO_SINT: + case ISD::STRICT_FP_TO_UINT: + case ISD::STRICT_FP_TO_SINT: // Promote the operation by extending the operand. - return PromoteFP_TO_INT(Op); + PromoteFP_TO_INT(Node, Results); + return; + case ISD::FP_ROUND: + case ISD::FP_EXTEND: + // These operations are used to do promotion so they can't be promoted + // themselves. + llvm_unreachable("Don't know how to promote this operation!"); } // There are currently two cases of vector promotion: @@ -536,91 +582,128 @@ SDValue VectorLegalizer::Promote(SDValue Op) { // same overall length. For example, x86 promotes ISD::AND v2i32 to v1i64. // 2) Extending a vector of floats to a vector of the same number of larger // floats. For example, AArch64 promotes ISD::FADD on v4f16 to v4f32. - MVT VT = Op.getSimpleValueType(); - assert(Op.getNode()->getNumValues() == 1 && + assert(Node->getNumValues() == 1 && "Can't promote a vector with multiple results!"); - MVT NVT = TLI.getTypeToPromoteTo(Op.getOpcode(), VT); - SDLoc dl(Op); - SmallVector<SDValue, 4> Operands(Op.getNumOperands()); - - for (unsigned j = 0; j != Op.getNumOperands(); ++j) { - if (Op.getOperand(j).getValueType().isVector()) - if (Op.getOperand(j) + MVT VT = Node->getSimpleValueType(0); + MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), VT); + SDLoc dl(Node); + SmallVector<SDValue, 4> Operands(Node->getNumOperands()); + + for (unsigned j = 0; j != Node->getNumOperands(); ++j) { + if (Node->getOperand(j).getValueType().isVector()) + if (Node->getOperand(j) .getValueType() .getVectorElementType() .isFloatingPoint() && NVT.isVector() && NVT.getVectorElementType().isFloatingPoint()) - Operands[j] = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Op.getOperand(j)); + Operands[j] = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(j)); else - Operands[j] = DAG.getNode(ISD::BITCAST, dl, NVT, Op.getOperand(j)); + Operands[j] = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(j)); else - Operands[j] = Op.getOperand(j); + Operands[j] = Node->getOperand(j); } - Op = DAG.getNode(Op.getOpcode(), dl, NVT, Operands, Op.getNode()->getFlags()); + SDValue Res = + DAG.getNode(Node->getOpcode(), dl, NVT, Operands, Node->getFlags()); + if ((VT.isFloatingPoint() && NVT.isFloatingPoint()) || (VT.isVector() && VT.getVectorElementType().isFloatingPoint() && NVT.isVector() && NVT.getVectorElementType().isFloatingPoint())) - return DAG.getNode(ISD::FP_ROUND, dl, VT, Op, DAG.getIntPtrConstant(0, dl)); + Res = DAG.getNode(ISD::FP_ROUND, dl, VT, Res, DAG.getIntPtrConstant(0, dl)); else - return DAG.getNode(ISD::BITCAST, dl, VT, Op); + Res = DAG.getNode(ISD::BITCAST, dl, VT, Res); + + Results.push_back(Res); } -SDValue VectorLegalizer::PromoteINT_TO_FP(SDValue Op) { +void VectorLegalizer::PromoteINT_TO_FP(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { // INT_TO_FP operations may require the input operand be promoted even // when the type is otherwise legal. - MVT VT = Op.getOperand(0).getSimpleValueType(); - MVT NVT = TLI.getTypeToPromoteTo(Op.getOpcode(), VT); + bool IsStrict = Node->isStrictFPOpcode(); + MVT VT = Node->getOperand(IsStrict ? 1 : 0).getSimpleValueType(); + MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), VT); assert(NVT.getVectorNumElements() == VT.getVectorNumElements() && "Vectors have different number of elements!"); - SDLoc dl(Op); - SmallVector<SDValue, 4> Operands(Op.getNumOperands()); + SDLoc dl(Node); + SmallVector<SDValue, 4> Operands(Node->getNumOperands()); - unsigned Opc = Op.getOpcode() == ISD::UINT_TO_FP ? ISD::ZERO_EXTEND : - ISD::SIGN_EXTEND; - for (unsigned j = 0; j != Op.getNumOperands(); ++j) { - if (Op.getOperand(j).getValueType().isVector()) - Operands[j] = DAG.getNode(Opc, dl, NVT, Op.getOperand(j)); + unsigned Opc = (Node->getOpcode() == ISD::UINT_TO_FP || + Node->getOpcode() == ISD::STRICT_UINT_TO_FP) + ? ISD::ZERO_EXTEND + : ISD::SIGN_EXTEND; + for (unsigned j = 0; j != Node->getNumOperands(); ++j) { + if (Node->getOperand(j).getValueType().isVector()) + Operands[j] = DAG.getNode(Opc, dl, NVT, Node->getOperand(j)); else - Operands[j] = Op.getOperand(j); + Operands[j] = Node->getOperand(j); + } + + if (IsStrict) { + SDValue Res = DAG.getNode(Node->getOpcode(), dl, + {Node->getValueType(0), MVT::Other}, Operands); + Results.push_back(Res); + Results.push_back(Res.getValue(1)); + return; } - return DAG.getNode(Op.getOpcode(), dl, Op.getValueType(), Operands); + SDValue Res = + DAG.getNode(Node->getOpcode(), dl, Node->getValueType(0), Operands); + Results.push_back(Res); } // For FP_TO_INT we promote the result type to a vector type with wider // elements and then truncate the result. This is different from the default // PromoteVector which uses bitcast to promote thus assumning that the // promoted vector type has the same overall size. -SDValue VectorLegalizer::PromoteFP_TO_INT(SDValue Op) { - MVT VT = Op.getSimpleValueType(); - MVT NVT = TLI.getTypeToPromoteTo(Op.getOpcode(), VT); +void VectorLegalizer::PromoteFP_TO_INT(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { + MVT VT = Node->getSimpleValueType(0); + MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), VT); + bool IsStrict = Node->isStrictFPOpcode(); assert(NVT.getVectorNumElements() == VT.getVectorNumElements() && "Vectors have different number of elements!"); - unsigned NewOpc = Op->getOpcode(); + unsigned NewOpc = Node->getOpcode(); // Change FP_TO_UINT to FP_TO_SINT if possible. // TODO: Should we only do this if FP_TO_UINT itself isn't legal? if (NewOpc == ISD::FP_TO_UINT && TLI.isOperationLegalOrCustom(ISD::FP_TO_SINT, NVT)) NewOpc = ISD::FP_TO_SINT; - SDLoc dl(Op); - SDValue Promoted = DAG.getNode(NewOpc, dl, NVT, Op.getOperand(0)); + if (NewOpc == ISD::STRICT_FP_TO_UINT && + TLI.isOperationLegalOrCustom(ISD::STRICT_FP_TO_SINT, NVT)) + NewOpc = ISD::STRICT_FP_TO_SINT; + + SDLoc dl(Node); + SDValue Promoted, Chain; + if (IsStrict) { + Promoted = DAG.getNode(NewOpc, dl, {NVT, MVT::Other}, + {Node->getOperand(0), Node->getOperand(1)}); + Chain = Promoted.getValue(1); + } else + Promoted = DAG.getNode(NewOpc, dl, NVT, Node->getOperand(0)); // Assert that the converted value fits in the original type. If it doesn't // (eg: because the value being converted is too big), then the result of the // original operation was undefined anyway, so the assert is still correct. - Promoted = DAG.getNode(Op->getOpcode() == ISD::FP_TO_UINT ? ISD::AssertZext - : ISD::AssertSext, - dl, NVT, Promoted, + if (Node->getOpcode() == ISD::FP_TO_UINT || + Node->getOpcode() == ISD::STRICT_FP_TO_UINT) + NewOpc = ISD::AssertZext; + else + NewOpc = ISD::AssertSext; + + Promoted = DAG.getNode(NewOpc, dl, NVT, Promoted, DAG.getValueType(VT.getScalarType())); - return DAG.getNode(ISD::TRUNCATE, dl, VT, Promoted); + Promoted = DAG.getNode(ISD::TRUNCATE, dl, VT, Promoted); + Results.push_back(Promoted); + if (IsStrict) + Results.push_back(Chain); } -SDValue VectorLegalizer::ExpandLoad(SDValue Op) { - LoadSDNode *LD = cast<LoadSDNode>(Op.getNode()); +std::pair<SDValue, SDValue> VectorLegalizer::ExpandLoad(SDNode *N) { + LoadSDNode *LD = cast<LoadSDNode>(N); EVT SrcVT = LD->getMemoryVT(); EVT SrcEltVT = SrcVT.getScalarType(); @@ -629,7 +712,7 @@ SDValue VectorLegalizer::ExpandLoad(SDValue Op) { SDValue NewChain; SDValue Value; if (SrcVT.getVectorNumElements() > 1 && !SrcEltVT.isByteSized()) { - SDLoc dl(Op); + SDLoc dl(N); SmallVector<SDValue, 8> Vals; SmallVector<SDValue, 8> LoadChains; @@ -741,130 +824,157 @@ SDValue VectorLegalizer::ExpandLoad(SDValue Op) { } NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, LoadChains); - Value = DAG.getBuildVector(Op.getNode()->getValueType(0), dl, Vals); + Value = DAG.getBuildVector(N->getValueType(0), dl, Vals); } else { - SDValue Scalarized = TLI.scalarizeVectorLoad(LD, DAG); - // Skip past MERGE_VALUE node if known. - if (Scalarized->getOpcode() == ISD::MERGE_VALUES) { - NewChain = Scalarized.getOperand(1); - Value = Scalarized.getOperand(0); - } else { - NewChain = Scalarized.getValue(1); - Value = Scalarized.getValue(0); - } + std::tie(Value, NewChain) = TLI.scalarizeVectorLoad(LD, DAG); } - AddLegalizedOperand(Op.getValue(0), Value); - AddLegalizedOperand(Op.getValue(1), NewChain); - - return (Op.getResNo() ? NewChain : Value); + return std::make_pair(Value, NewChain); } -SDValue VectorLegalizer::ExpandStore(SDValue Op) { - StoreSDNode *ST = cast<StoreSDNode>(Op.getNode()); +SDValue VectorLegalizer::ExpandStore(SDNode *N) { + StoreSDNode *ST = cast<StoreSDNode>(N); SDValue TF = TLI.scalarizeVectorStore(ST, DAG); - AddLegalizedOperand(Op, TF); return TF; } -SDValue VectorLegalizer::Expand(SDValue Op) { - switch (Op->getOpcode()) { +void VectorLegalizer::Expand(SDNode *Node, SmallVectorImpl<SDValue> &Results) { + SDValue Tmp; + switch (Node->getOpcode()) { + case ISD::MERGE_VALUES: + for (unsigned i = 0, e = Node->getNumValues(); i != e; ++i) + Results.push_back(Node->getOperand(i)); + return; case ISD::SIGN_EXTEND_INREG: - return ExpandSEXTINREG(Op); + Results.push_back(ExpandSEXTINREG(Node)); + return; case ISD::ANY_EXTEND_VECTOR_INREG: - return ExpandANY_EXTEND_VECTOR_INREG(Op); + Results.push_back(ExpandANY_EXTEND_VECTOR_INREG(Node)); + return; case ISD::SIGN_EXTEND_VECTOR_INREG: - return ExpandSIGN_EXTEND_VECTOR_INREG(Op); + Results.push_back(ExpandSIGN_EXTEND_VECTOR_INREG(Node)); + return; case ISD::ZERO_EXTEND_VECTOR_INREG: - return ExpandZERO_EXTEND_VECTOR_INREG(Op); + Results.push_back(ExpandZERO_EXTEND_VECTOR_INREG(Node)); + return; case ISD::BSWAP: - return ExpandBSWAP(Op); + Results.push_back(ExpandBSWAP(Node)); + return; case ISD::VSELECT: - return ExpandVSELECT(Op); + Results.push_back(ExpandVSELECT(Node)); + return; case ISD::SELECT: - return ExpandSELECT(Op); + Results.push_back(ExpandSELECT(Node)); + return; case ISD::FP_TO_UINT: - return ExpandFP_TO_UINT(Op); + ExpandFP_TO_UINT(Node, Results); + return; case ISD::UINT_TO_FP: - return ExpandUINT_TO_FLOAT(Op); + ExpandUINT_TO_FLOAT(Node, Results); + return; case ISD::FNEG: - return ExpandFNEG(Op); + Results.push_back(ExpandFNEG(Node)); + return; case ISD::FSUB: - return ExpandFSUB(Op); + ExpandFSUB(Node, Results); + return; case ISD::SETCC: - return UnrollVSETCC(Op); + Results.push_back(UnrollVSETCC(Node)); + return; case ISD::ABS: - return ExpandABS(Op); + if (TLI.expandABS(Node, Tmp, DAG)) { + Results.push_back(Tmp); + return; + } + break; case ISD::BITREVERSE: - return ExpandBITREVERSE(Op); + ExpandBITREVERSE(Node, Results); + return; case ISD::CTPOP: - return ExpandCTPOP(Op); + if (TLI.expandCTPOP(Node, Tmp, DAG)) { + Results.push_back(Tmp); + return; + } + break; case ISD::CTLZ: case ISD::CTLZ_ZERO_UNDEF: - return ExpandCTLZ(Op); + if (TLI.expandCTLZ(Node, Tmp, DAG)) { + Results.push_back(Tmp); + return; + } + break; case ISD::CTTZ: case ISD::CTTZ_ZERO_UNDEF: - return ExpandCTTZ(Op); + if (TLI.expandCTTZ(Node, Tmp, DAG)) { + Results.push_back(Tmp); + return; + } + break; case ISD::FSHL: case ISD::FSHR: - return ExpandFunnelShift(Op); + if (TLI.expandFunnelShift(Node, Tmp, DAG)) { + Results.push_back(Tmp); + return; + } + break; case ISD::ROTL: case ISD::ROTR: - return ExpandROT(Op); + if (TLI.expandROT(Node, Tmp, DAG)) { + Results.push_back(Tmp); + return; + } + break; case ISD::FMINNUM: case ISD::FMAXNUM: - return ExpandFMINNUM_FMAXNUM(Op); + if (SDValue Expanded = TLI.expandFMINNUM_FMAXNUM(Node, DAG)) { + Results.push_back(Expanded); + return; + } + break; case ISD::UADDO: case ISD::USUBO: - return ExpandUADDSUBO(Op); + ExpandUADDSUBO(Node, Results); + return; case ISD::SADDO: case ISD::SSUBO: - return ExpandSADDSUBO(Op); + ExpandSADDSUBO(Node, Results); + return; case ISD::UMULO: case ISD::SMULO: - return ExpandMULO(Op); + ExpandMULO(Node, Results); + return; case ISD::USUBSAT: case ISD::SSUBSAT: case ISD::UADDSAT: case ISD::SADDSAT: - return ExpandAddSubSat(Op); + if (SDValue Expanded = TLI.expandAddSubSat(Node, DAG)) { + Results.push_back(Expanded); + return; + } + break; case ISD::SMULFIX: case ISD::UMULFIX: - return ExpandFixedPointMul(Op); + if (SDValue Expanded = TLI.expandFixedPointMul(Node, DAG)) { + Results.push_back(Expanded); + return; + } + break; case ISD::SMULFIXSAT: case ISD::UMULFIXSAT: // FIXME: We do not expand SMULFIXSAT/UMULFIXSAT here yet, not sure exactly // why. Maybe it results in worse codegen compared to the unroll for some // targets? This should probably be investigated. And if we still prefer to // unroll an explanation could be helpful. - return DAG.UnrollVectorOp(Op.getNode()); - case ISD::STRICT_FADD: - case ISD::STRICT_FSUB: - case ISD::STRICT_FMUL: - case ISD::STRICT_FDIV: - case ISD::STRICT_FREM: - case ISD::STRICT_FSQRT: - case ISD::STRICT_FMA: - case ISD::STRICT_FPOW: - case ISD::STRICT_FPOWI: - case ISD::STRICT_FSIN: - case ISD::STRICT_FCOS: - case ISD::STRICT_FEXP: - case ISD::STRICT_FEXP2: - case ISD::STRICT_FLOG: - case ISD::STRICT_FLOG10: - case ISD::STRICT_FLOG2: - case ISD::STRICT_FRINT: - case ISD::STRICT_FNEARBYINT: - case ISD::STRICT_FMAXNUM: - case ISD::STRICT_FMINNUM: - case ISD::STRICT_FCEIL: - case ISD::STRICT_FFLOOR: - case ISD::STRICT_FROUND: - case ISD::STRICT_FTRUNC: - case ISD::STRICT_FP_TO_SINT: - case ISD::STRICT_FP_TO_UINT: - return ExpandStrictFPOp(Op); + break; + case ISD::SDIVFIX: + case ISD::UDIVFIX: + Results.push_back(ExpandFixedPointDiv(Node)); + return; +#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \ + case ISD::STRICT_##DAGN: +#include "llvm/IR/ConstrainedOps.def" + ExpandStrictFPOp(Node, Results); + return; case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: @@ -878,22 +988,23 @@ SDValue VectorLegalizer::Expand(SDValue Op) { case ISD::VECREDUCE_FMUL: case ISD::VECREDUCE_FMAX: case ISD::VECREDUCE_FMIN: - return TLI.expandVecReduce(Op.getNode(), DAG); - default: - return DAG.UnrollVectorOp(Op.getNode()); + Results.push_back(TLI.expandVecReduce(Node, DAG)); + return; } + + Results.push_back(DAG.UnrollVectorOp(Node)); } -SDValue VectorLegalizer::ExpandSELECT(SDValue Op) { +SDValue VectorLegalizer::ExpandSELECT(SDNode *Node) { // Lower a select instruction where the condition is a scalar and the // operands are vectors. Lower this select to VSELECT and implement it // using XOR AND OR. The selector bit is broadcasted. - EVT VT = Op.getValueType(); - SDLoc DL(Op); + EVT VT = Node->getValueType(0); + SDLoc DL(Node); - SDValue Mask = Op.getOperand(0); - SDValue Op1 = Op.getOperand(1); - SDValue Op2 = Op.getOperand(2); + SDValue Mask = Node->getOperand(0); + SDValue Op1 = Node->getOperand(1); + SDValue Op2 = Node->getOperand(2); assert(VT.isVector() && !Mask.getValueType().isVector() && Op1.getValueType() == Op2.getValueType() && "Invalid type"); @@ -907,7 +1018,7 @@ SDValue VectorLegalizer::ExpandSELECT(SDValue Op) { TLI.getOperationAction(ISD::XOR, VT) == TargetLowering::Expand || TLI.getOperationAction(ISD::OR, VT) == TargetLowering::Expand || TLI.getOperationAction(ISD::BUILD_VECTOR, VT) == TargetLowering::Expand) - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(Node); // Generate a mask operand. EVT MaskTy = VT.changeVectorElementTypeToInteger(); @@ -936,36 +1047,35 @@ SDValue VectorLegalizer::ExpandSELECT(SDValue Op) { Op1 = DAG.getNode(ISD::AND, DL, MaskTy, Op1, Mask); Op2 = DAG.getNode(ISD::AND, DL, MaskTy, Op2, NotMask); SDValue Val = DAG.getNode(ISD::OR, DL, MaskTy, Op1, Op2); - return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Val); + return DAG.getNode(ISD::BITCAST, DL, Node->getValueType(0), Val); } -SDValue VectorLegalizer::ExpandSEXTINREG(SDValue Op) { - EVT VT = Op.getValueType(); +SDValue VectorLegalizer::ExpandSEXTINREG(SDNode *Node) { + EVT VT = Node->getValueType(0); // Make sure that the SRA and SHL instructions are available. if (TLI.getOperationAction(ISD::SRA, VT) == TargetLowering::Expand || TLI.getOperationAction(ISD::SHL, VT) == TargetLowering::Expand) - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(Node); - SDLoc DL(Op); - EVT OrigTy = cast<VTSDNode>(Op->getOperand(1))->getVT(); + SDLoc DL(Node); + EVT OrigTy = cast<VTSDNode>(Node->getOperand(1))->getVT(); unsigned BW = VT.getScalarSizeInBits(); unsigned OrigBW = OrigTy.getScalarSizeInBits(); SDValue ShiftSz = DAG.getConstant(BW - OrigBW, DL, VT); - Op = Op.getOperand(0); - Op = DAG.getNode(ISD::SHL, DL, VT, Op, ShiftSz); + SDValue Op = DAG.getNode(ISD::SHL, DL, VT, Node->getOperand(0), ShiftSz); return DAG.getNode(ISD::SRA, DL, VT, Op, ShiftSz); } // Generically expand a vector anyext in register to a shuffle of the relevant // lanes into the appropriate locations, with other lanes left undef. -SDValue VectorLegalizer::ExpandANY_EXTEND_VECTOR_INREG(SDValue Op) { - SDLoc DL(Op); - EVT VT = Op.getValueType(); +SDValue VectorLegalizer::ExpandANY_EXTEND_VECTOR_INREG(SDNode *Node) { + SDLoc DL(Node); + EVT VT = Node->getValueType(0); int NumElements = VT.getVectorNumElements(); - SDValue Src = Op.getOperand(0); + SDValue Src = Node->getOperand(0); EVT SrcVT = Src.getValueType(); int NumSrcElements = SrcVT.getVectorNumElements(); @@ -997,15 +1107,15 @@ SDValue VectorLegalizer::ExpandANY_EXTEND_VECTOR_INREG(SDValue Op) { DAG.getVectorShuffle(SrcVT, DL, Src, DAG.getUNDEF(SrcVT), ShuffleMask)); } -SDValue VectorLegalizer::ExpandSIGN_EXTEND_VECTOR_INREG(SDValue Op) { - SDLoc DL(Op); - EVT VT = Op.getValueType(); - SDValue Src = Op.getOperand(0); +SDValue VectorLegalizer::ExpandSIGN_EXTEND_VECTOR_INREG(SDNode *Node) { + SDLoc DL(Node); + EVT VT = Node->getValueType(0); + SDValue Src = Node->getOperand(0); EVT SrcVT = Src.getValueType(); // First build an any-extend node which can be legalized above when we // recurse through it. - Op = DAG.getNode(ISD::ANY_EXTEND_VECTOR_INREG, DL, VT, Src); + SDValue Op = DAG.getNode(ISD::ANY_EXTEND_VECTOR_INREG, DL, VT, Src); // Now we need sign extend. Do this by shifting the elements. Even if these // aren't legal operations, they have a better chance of being legalized @@ -1021,11 +1131,11 @@ SDValue VectorLegalizer::ExpandSIGN_EXTEND_VECTOR_INREG(SDValue Op) { // Generically expand a vector zext in register to a shuffle of the relevant // lanes into the appropriate locations, a blend of zero into the high bits, // and a bitcast to the wider element type. -SDValue VectorLegalizer::ExpandZERO_EXTEND_VECTOR_INREG(SDValue Op) { - SDLoc DL(Op); - EVT VT = Op.getValueType(); +SDValue VectorLegalizer::ExpandZERO_EXTEND_VECTOR_INREG(SDNode *Node) { + SDLoc DL(Node); + EVT VT = Node->getValueType(0); int NumElements = VT.getVectorNumElements(); - SDValue Src = Op.getOperand(0); + SDValue Src = Node->getOperand(0); EVT SrcVT = Src.getValueType(); int NumSrcElements = SrcVT.getVectorNumElements(); @@ -1068,8 +1178,8 @@ static void createBSWAPShuffleMask(EVT VT, SmallVectorImpl<int> &ShuffleMask) { ShuffleMask.push_back((I * ScalarSizeInBytes) + J); } -SDValue VectorLegalizer::ExpandBSWAP(SDValue Op) { - EVT VT = Op.getValueType(); +SDValue VectorLegalizer::ExpandBSWAP(SDNode *Node) { + EVT VT = Node->getValueType(0); // Generate a byte wise shuffle mask for the BSWAP. SmallVector<int, 16> ShuffleMask; @@ -1078,20 +1188,24 @@ SDValue VectorLegalizer::ExpandBSWAP(SDValue Op) { // Only emit a shuffle if the mask is legal. if (!TLI.isShuffleMaskLegal(ShuffleMask, ByteVT)) - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(Node); - SDLoc DL(Op); - Op = DAG.getNode(ISD::BITCAST, DL, ByteVT, Op.getOperand(0)); + SDLoc DL(Node); + SDValue Op = DAG.getNode(ISD::BITCAST, DL, ByteVT, Node->getOperand(0)); Op = DAG.getVectorShuffle(ByteVT, DL, Op, DAG.getUNDEF(ByteVT), ShuffleMask); return DAG.getNode(ISD::BITCAST, DL, VT, Op); } -SDValue VectorLegalizer::ExpandBITREVERSE(SDValue Op) { - EVT VT = Op.getValueType(); +void VectorLegalizer::ExpandBITREVERSE(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { + EVT VT = Node->getValueType(0); // If we have the scalar operation, it's probably cheaper to unroll it. - if (TLI.isOperationLegalOrCustom(ISD::BITREVERSE, VT.getScalarType())) - return DAG.UnrollVectorOp(Op.getNode()); + if (TLI.isOperationLegalOrCustom(ISD::BITREVERSE, VT.getScalarType())) { + SDValue Tmp = DAG.UnrollVectorOp(Node); + Results.push_back(Tmp); + return; + } // If the vector element width is a whole number of bytes, test if its legal // to BSWAP shuffle the bytes and then perform the BITREVERSE on the byte @@ -1108,35 +1222,39 @@ SDValue VectorLegalizer::ExpandBITREVERSE(SDValue Op) { TLI.isOperationLegalOrCustom(ISD::SRL, ByteVT) && TLI.isOperationLegalOrCustomOrPromote(ISD::AND, ByteVT) && TLI.isOperationLegalOrCustomOrPromote(ISD::OR, ByteVT)))) { - SDLoc DL(Op); - Op = DAG.getNode(ISD::BITCAST, DL, ByteVT, Op.getOperand(0)); + SDLoc DL(Node); + SDValue Op = DAG.getNode(ISD::BITCAST, DL, ByteVT, Node->getOperand(0)); Op = DAG.getVectorShuffle(ByteVT, DL, Op, DAG.getUNDEF(ByteVT), BSWAPMask); Op = DAG.getNode(ISD::BITREVERSE, DL, ByteVT, Op); - return DAG.getNode(ISD::BITCAST, DL, VT, Op); + Op = DAG.getNode(ISD::BITCAST, DL, VT, Op); + Results.push_back(Op); + return; } } // If we have the appropriate vector bit operations, it is better to use them // than unrolling and expanding each component. - if (!TLI.isOperationLegalOrCustom(ISD::SHL, VT) || - !TLI.isOperationLegalOrCustom(ISD::SRL, VT) || - !TLI.isOperationLegalOrCustomOrPromote(ISD::AND, VT) || - !TLI.isOperationLegalOrCustomOrPromote(ISD::OR, VT)) - return DAG.UnrollVectorOp(Op.getNode()); - - // Let LegalizeDAG handle this later. - return Op; + if (TLI.isOperationLegalOrCustom(ISD::SHL, VT) && + TLI.isOperationLegalOrCustom(ISD::SRL, VT) && + TLI.isOperationLegalOrCustomOrPromote(ISD::AND, VT) && + TLI.isOperationLegalOrCustomOrPromote(ISD::OR, VT)) + // Let LegalizeDAG handle this later. + return; + + // Otherwise unroll. + SDValue Tmp = DAG.UnrollVectorOp(Node); + Results.push_back(Tmp); } -SDValue VectorLegalizer::ExpandVSELECT(SDValue Op) { +SDValue VectorLegalizer::ExpandVSELECT(SDNode *Node) { // Implement VSELECT in terms of XOR, AND, OR // on platforms which do not support blend natively. - SDLoc DL(Op); + SDLoc DL(Node); - SDValue Mask = Op.getOperand(0); - SDValue Op1 = Op.getOperand(1); - SDValue Op2 = Op.getOperand(2); + SDValue Mask = Node->getOperand(0); + SDValue Op1 = Node->getOperand(1); + SDValue Op2 = Node->getOperand(2); EVT VT = Mask.getValueType(); @@ -1152,13 +1270,13 @@ SDValue VectorLegalizer::ExpandVSELECT(SDValue Op) { TLI.getOperationAction(ISD::OR, VT) == TargetLowering::Expand || TLI.getBooleanContents(Op1.getValueType()) != TargetLowering::ZeroOrNegativeOneBooleanContent) - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(Node); // If the mask and the type are different sizes, unroll the vector op. This // can occur when getSetCCResultType returns something that is different in // size from the operand types. For example, v4i8 = select v4i32, v4i8, v4i8. if (VT.getSizeInBits() != Op1.getValueSizeInBits()) - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(Node); // Bitcast the operands to be the same type as the mask. // This is needed when we select between FP types because @@ -1173,46 +1291,61 @@ SDValue VectorLegalizer::ExpandVSELECT(SDValue Op) { Op1 = DAG.getNode(ISD::AND, DL, VT, Op1, Mask); Op2 = DAG.getNode(ISD::AND, DL, VT, Op2, NotMask); SDValue Val = DAG.getNode(ISD::OR, DL, VT, Op1, Op2); - return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Val); -} - -SDValue VectorLegalizer::ExpandABS(SDValue Op) { - // Attempt to expand using TargetLowering. - SDValue Result; - if (TLI.expandABS(Op.getNode(), Result, DAG)) - return Result; - - // Otherwise go ahead and unroll. - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.getNode(ISD::BITCAST, DL, Node->getValueType(0), Val); } -SDValue VectorLegalizer::ExpandFP_TO_UINT(SDValue Op) { +void VectorLegalizer::ExpandFP_TO_UINT(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { // Attempt to expand using TargetLowering. SDValue Result, Chain; - if (TLI.expandFP_TO_UINT(Op.getNode(), Result, Chain, DAG)) { - if (Op.getNode()->isStrictFPOpcode()) - // Relink the chain - DAG.ReplaceAllUsesOfValueWith(Op.getValue(1), Chain); - return Result; + if (TLI.expandFP_TO_UINT(Node, Result, Chain, DAG)) { + Results.push_back(Result); + if (Node->isStrictFPOpcode()) + Results.push_back(Chain); + return; } // Otherwise go ahead and unroll. - return DAG.UnrollVectorOp(Op.getNode()); + if (Node->isStrictFPOpcode()) { + UnrollStrictFPOp(Node, Results); + return; + } + + Results.push_back(DAG.UnrollVectorOp(Node)); } -SDValue VectorLegalizer::ExpandUINT_TO_FLOAT(SDValue Op) { - EVT VT = Op.getOperand(0).getValueType(); - SDLoc DL(Op); +void VectorLegalizer::ExpandUINT_TO_FLOAT(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { + bool IsStrict = Node->isStrictFPOpcode(); + unsigned OpNo = IsStrict ? 1 : 0; + SDValue Src = Node->getOperand(OpNo); + EVT VT = Src.getValueType(); + SDLoc DL(Node); // Attempt to expand using TargetLowering. SDValue Result; - if (TLI.expandUINT_TO_FP(Op.getNode(), Result, DAG)) - return Result; + SDValue Chain; + if (TLI.expandUINT_TO_FP(Node, Result, Chain, DAG)) { + Results.push_back(Result); + if (IsStrict) + Results.push_back(Chain); + return; + } // Make sure that the SINT_TO_FP and SRL instructions are available. - if (TLI.getOperationAction(ISD::SINT_TO_FP, VT) == TargetLowering::Expand || - TLI.getOperationAction(ISD::SRL, VT) == TargetLowering::Expand) - return DAG.UnrollVectorOp(Op.getNode()); + if (((!IsStrict && TLI.getOperationAction(ISD::SINT_TO_FP, VT) == + TargetLowering::Expand) || + (IsStrict && TLI.getOperationAction(ISD::STRICT_SINT_TO_FP, VT) == + TargetLowering::Expand)) || + TLI.getOperationAction(ISD::SRL, VT) == TargetLowering::Expand) { + if (IsStrict) { + UnrollStrictFPOp(Node, Results); + return; + } + + Results.push_back(DAG.UnrollVectorOp(Node)); + return; + } unsigned BW = VT.getScalarSizeInBits(); assert((BW == 64 || BW == 32) && @@ -1227,153 +1360,141 @@ SDValue VectorLegalizer::ExpandUINT_TO_FLOAT(SDValue Op) { SDValue HalfWordMask = DAG.getConstant(HWMask, DL, VT); // Two to the power of half-word-size. - SDValue TWOHW = DAG.getConstantFP(1ULL << (BW / 2), DL, Op.getValueType()); + SDValue TWOHW = + DAG.getConstantFP(1ULL << (BW / 2), DL, Node->getValueType(0)); // Clear upper part of LO, lower HI - SDValue HI = DAG.getNode(ISD::SRL, DL, VT, Op.getOperand(0), HalfWord); - SDValue LO = DAG.getNode(ISD::AND, DL, VT, Op.getOperand(0), HalfWordMask); + SDValue HI = DAG.getNode(ISD::SRL, DL, VT, Src, HalfWord); + SDValue LO = DAG.getNode(ISD::AND, DL, VT, Src, HalfWordMask); + + if (IsStrict) { + // Convert hi and lo to floats + // Convert the hi part back to the upper values + // TODO: Can any fast-math-flags be set on these nodes? + SDValue fHI = DAG.getNode(ISD::STRICT_SINT_TO_FP, DL, + {Node->getValueType(0), MVT::Other}, + {Node->getOperand(0), HI}); + fHI = DAG.getNode(ISD::STRICT_FMUL, DL, {Node->getValueType(0), MVT::Other}, + {fHI.getValue(1), fHI, TWOHW}); + SDValue fLO = DAG.getNode(ISD::STRICT_SINT_TO_FP, DL, + {Node->getValueType(0), MVT::Other}, + {Node->getOperand(0), LO}); + + SDValue TF = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, fHI.getValue(1), + fLO.getValue(1)); + + // Add the two halves + SDValue Result = + DAG.getNode(ISD::STRICT_FADD, DL, {Node->getValueType(0), MVT::Other}, + {TF, fHI, fLO}); + + Results.push_back(Result); + Results.push_back(Result.getValue(1)); + return; + } // Convert hi and lo to floats // Convert the hi part back to the upper values // TODO: Can any fast-math-flags be set on these nodes? - SDValue fHI = DAG.getNode(ISD::SINT_TO_FP, DL, Op.getValueType(), HI); - fHI = DAG.getNode(ISD::FMUL, DL, Op.getValueType(), fHI, TWOHW); - SDValue fLO = DAG.getNode(ISD::SINT_TO_FP, DL, Op.getValueType(), LO); + SDValue fHI = DAG.getNode(ISD::SINT_TO_FP, DL, Node->getValueType(0), HI); + fHI = DAG.getNode(ISD::FMUL, DL, Node->getValueType(0), fHI, TWOHW); + SDValue fLO = DAG.getNode(ISD::SINT_TO_FP, DL, Node->getValueType(0), LO); // Add the two halves - return DAG.getNode(ISD::FADD, DL, Op.getValueType(), fHI, fLO); + Results.push_back( + DAG.getNode(ISD::FADD, DL, Node->getValueType(0), fHI, fLO)); } -SDValue VectorLegalizer::ExpandFNEG(SDValue Op) { - if (TLI.isOperationLegalOrCustom(ISD::FSUB, Op.getValueType())) { - SDLoc DL(Op); - SDValue Zero = DAG.getConstantFP(-0.0, DL, Op.getValueType()); +SDValue VectorLegalizer::ExpandFNEG(SDNode *Node) { + if (TLI.isOperationLegalOrCustom(ISD::FSUB, Node->getValueType(0))) { + SDLoc DL(Node); + SDValue Zero = DAG.getConstantFP(-0.0, DL, Node->getValueType(0)); // TODO: If FNEG had fast-math-flags, they'd get propagated to this FSUB. - return DAG.getNode(ISD::FSUB, DL, Op.getValueType(), - Zero, Op.getOperand(0)); + return DAG.getNode(ISD::FSUB, DL, Node->getValueType(0), Zero, + Node->getOperand(0)); } - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(Node); } -SDValue VectorLegalizer::ExpandFSUB(SDValue Op) { +void VectorLegalizer::ExpandFSUB(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { // For floating-point values, (a-b) is the same as a+(-b). If FNEG is legal, // we can defer this to operation legalization where it will be lowered as // a+(-b). - EVT VT = Op.getValueType(); + EVT VT = Node->getValueType(0); if (TLI.isOperationLegalOrCustom(ISD::FNEG, VT) && TLI.isOperationLegalOrCustom(ISD::FADD, VT)) - return Op; // Defer to LegalizeDAG - - return DAG.UnrollVectorOp(Op.getNode()); -} + return; // Defer to LegalizeDAG -SDValue VectorLegalizer::ExpandCTPOP(SDValue Op) { - SDValue Result; - if (TLI.expandCTPOP(Op.getNode(), Result, DAG)) - return Result; - - return DAG.UnrollVectorOp(Op.getNode()); -} - -SDValue VectorLegalizer::ExpandCTLZ(SDValue Op) { - SDValue Result; - if (TLI.expandCTLZ(Op.getNode(), Result, DAG)) - return Result; - - return DAG.UnrollVectorOp(Op.getNode()); + SDValue Tmp = DAG.UnrollVectorOp(Node); + Results.push_back(Tmp); } -SDValue VectorLegalizer::ExpandCTTZ(SDValue Op) { - SDValue Result; - if (TLI.expandCTTZ(Op.getNode(), Result, DAG)) - return Result; - - return DAG.UnrollVectorOp(Op.getNode()); -} - -SDValue VectorLegalizer::ExpandFunnelShift(SDValue Op) { - SDValue Result; - if (TLI.expandFunnelShift(Op.getNode(), Result, DAG)) - return Result; - - return DAG.UnrollVectorOp(Op.getNode()); -} - -SDValue VectorLegalizer::ExpandROT(SDValue Op) { - SDValue Result; - if (TLI.expandROT(Op.getNode(), Result, DAG)) - return Result; - - return DAG.UnrollVectorOp(Op.getNode()); -} - -SDValue VectorLegalizer::ExpandFMINNUM_FMAXNUM(SDValue Op) { - if (SDValue Expanded = TLI.expandFMINNUM_FMAXNUM(Op.getNode(), DAG)) - return Expanded; - return DAG.UnrollVectorOp(Op.getNode()); -} - -SDValue VectorLegalizer::ExpandUADDSUBO(SDValue Op) { +void VectorLegalizer::ExpandUADDSUBO(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { SDValue Result, Overflow; - TLI.expandUADDSUBO(Op.getNode(), Result, Overflow, DAG); - - if (Op.getResNo() == 0) { - AddLegalizedOperand(Op.getValue(1), LegalizeOp(Overflow)); - return Result; - } else { - AddLegalizedOperand(Op.getValue(0), LegalizeOp(Result)); - return Overflow; - } + TLI.expandUADDSUBO(Node, Result, Overflow, DAG); + Results.push_back(Result); + Results.push_back(Overflow); } -SDValue VectorLegalizer::ExpandSADDSUBO(SDValue Op) { +void VectorLegalizer::ExpandSADDSUBO(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { SDValue Result, Overflow; - TLI.expandSADDSUBO(Op.getNode(), Result, Overflow, DAG); - - if (Op.getResNo() == 0) { - AddLegalizedOperand(Op.getValue(1), LegalizeOp(Overflow)); - return Result; - } else { - AddLegalizedOperand(Op.getValue(0), LegalizeOp(Result)); - return Overflow; - } + TLI.expandSADDSUBO(Node, Result, Overflow, DAG); + Results.push_back(Result); + Results.push_back(Overflow); } -SDValue VectorLegalizer::ExpandMULO(SDValue Op) { +void VectorLegalizer::ExpandMULO(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { SDValue Result, Overflow; - if (!TLI.expandMULO(Op.getNode(), Result, Overflow, DAG)) - std::tie(Result, Overflow) = DAG.UnrollVectorOverflowOp(Op.getNode()); + if (!TLI.expandMULO(Node, Result, Overflow, DAG)) + std::tie(Result, Overflow) = DAG.UnrollVectorOverflowOp(Node); - if (Op.getResNo() == 0) { - AddLegalizedOperand(Op.getValue(1), LegalizeOp(Overflow)); - return Result; - } else { - AddLegalizedOperand(Op.getValue(0), LegalizeOp(Result)); - return Overflow; - } + Results.push_back(Result); + Results.push_back(Overflow); } -SDValue VectorLegalizer::ExpandAddSubSat(SDValue Op) { - if (SDValue Expanded = TLI.expandAddSubSat(Op.getNode(), DAG)) +SDValue VectorLegalizer::ExpandFixedPointDiv(SDNode *Node) { + SDNode *N = Node; + if (SDValue Expanded = TLI.expandFixedPointDiv(N->getOpcode(), SDLoc(N), + N->getOperand(0), N->getOperand(1), N->getConstantOperandVal(2), DAG)) return Expanded; - return DAG.UnrollVectorOp(Op.getNode()); + return DAG.UnrollVectorOp(N); } -SDValue VectorLegalizer::ExpandFixedPointMul(SDValue Op) { - if (SDValue Expanded = TLI.expandFixedPointMul(Op.getNode(), DAG)) - return Expanded; - return DAG.UnrollVectorOp(Op.getNode()); +void VectorLegalizer::ExpandStrictFPOp(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { + if (Node->getOpcode() == ISD::STRICT_UINT_TO_FP) { + ExpandUINT_TO_FLOAT(Node, Results); + return; + } + if (Node->getOpcode() == ISD::STRICT_FP_TO_UINT) { + ExpandFP_TO_UINT(Node, Results); + return; + } + + UnrollStrictFPOp(Node, Results); } -SDValue VectorLegalizer::ExpandStrictFPOp(SDValue Op) { - EVT VT = Op.getValueType(); +void VectorLegalizer::UnrollStrictFPOp(SDNode *Node, + SmallVectorImpl<SDValue> &Results) { + EVT VT = Node->getValueType(0); EVT EltVT = VT.getVectorElementType(); unsigned NumElems = VT.getVectorNumElements(); - unsigned NumOpers = Op.getNumOperands(); + unsigned NumOpers = Node->getNumOperands(); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - EVT ValueVTs[] = {EltVT, MVT::Other}; - SDValue Chain = Op.getOperand(0); - SDLoc dl(Op); + + EVT TmpEltVT = EltVT; + if (Node->getOpcode() == ISD::STRICT_FSETCC || + Node->getOpcode() == ISD::STRICT_FSETCCS) + TmpEltVT = TLI.getSetCCResultType(DAG.getDataLayout(), + *DAG.getContext(), TmpEltVT); + + EVT ValueVTs[] = {TmpEltVT, MVT::Other}; + SDValue Chain = Node->getOperand(0); + SDLoc dl(Node); SmallVector<SDValue, 32> OpValues; SmallVector<SDValue, 32> OpChains; @@ -1387,7 +1508,7 @@ SDValue VectorLegalizer::ExpandStrictFPOp(SDValue Op) { // Now process the remaining operands. for (unsigned j = 1; j < NumOpers; ++j) { - SDValue Oper = Op.getOperand(j); + SDValue Oper = Node->getOperand(j); EVT OperVT = Oper.getValueType(); if (OperVT.isVector()) @@ -1397,28 +1518,37 @@ SDValue VectorLegalizer::ExpandStrictFPOp(SDValue Op) { Opers.push_back(Oper); } - SDValue ScalarOp = DAG.getNode(Op->getOpcode(), dl, ValueVTs, Opers); + SDValue ScalarOp = DAG.getNode(Node->getOpcode(), dl, ValueVTs, Opers); + SDValue ScalarResult = ScalarOp.getValue(0); + SDValue ScalarChain = ScalarOp.getValue(1); + + if (Node->getOpcode() == ISD::STRICT_FSETCC || + Node->getOpcode() == ISD::STRICT_FSETCCS) + ScalarResult = DAG.getSelect(dl, EltVT, ScalarResult, + DAG.getConstant(APInt::getAllOnesValue + (EltVT.getSizeInBits()), dl, EltVT), + DAG.getConstant(0, dl, EltVT)); - OpValues.push_back(ScalarOp.getValue(0)); - OpChains.push_back(ScalarOp.getValue(1)); + OpValues.push_back(ScalarResult); + OpChains.push_back(ScalarChain); } SDValue Result = DAG.getBuildVector(VT, dl, OpValues); SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OpChains); - AddLegalizedOperand(Op.getValue(0), Result); - AddLegalizedOperand(Op.getValue(1), NewChain); - - return Op.getResNo() ? NewChain : Result; + Results.push_back(Result); + Results.push_back(NewChain); } -SDValue VectorLegalizer::UnrollVSETCC(SDValue Op) { - EVT VT = Op.getValueType(); +SDValue VectorLegalizer::UnrollVSETCC(SDNode *Node) { + EVT VT = Node->getValueType(0); unsigned NumElems = VT.getVectorNumElements(); EVT EltVT = VT.getVectorElementType(); - SDValue LHS = Op.getOperand(0), RHS = Op.getOperand(1), CC = Op.getOperand(2); + SDValue LHS = Node->getOperand(0); + SDValue RHS = Node->getOperand(1); + SDValue CC = Node->getOperand(2); EVT TmpEltVT = LHS.getValueType().getVectorElementType(); - SDLoc dl(Op); + SDLoc dl(Node); SmallVector<SDValue, 8> Ops(NumElems); for (unsigned i = 0; i < NumElems; ++i) { SDValue LHSElem = DAG.getNode( |