summaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp1020
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(