#include "LegalizeTypes.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TypeSize.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "legalize-types"
void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
LLVM_DEBUG(dbgs() << "Scalarize node result " << ResNo << ": "; N->dump(&DAG);
dbgs() << "\n");
SDValue R = SDValue();
switch (N->getOpcode()) {
default:
#ifndef NDEBUG
dbgs() << "ScalarizeVectorResult #" << ResNo << ": ";
N->dump(&DAG);
dbgs() << "\n";
#endif
report_fatal_error("Do not know how to scalarize the result of this "
"operator!\n");
case ISD::MERGE_VALUES: R = ScalarizeVecRes_MERGE_VALUES(N, ResNo);break;
case ISD::BITCAST: R = ScalarizeVecRes_BITCAST(N); break;
case ISD::BUILD_VECTOR: R = ScalarizeVecRes_BUILD_VECTOR(N); break;
case ISD::EXTRACT_SUBVECTOR: R = ScalarizeVecRes_EXTRACT_SUBVECTOR(N); break;
case ISD::FP_ROUND: R = ScalarizeVecRes_FP_ROUND(N); break;
case ISD::FPOWI: R = ScalarizeVecRes_FPOWI(N); break;
case ISD::INSERT_VECTOR_ELT: R = ScalarizeVecRes_INSERT_VECTOR_ELT(N); break;
case ISD::LOAD: R = ScalarizeVecRes_LOAD(cast<LoadSDNode>(N));break;
case ISD::SCALAR_TO_VECTOR: R = ScalarizeVecRes_SCALAR_TO_VECTOR(N); break;
case ISD::SIGN_EXTEND_INREG: R = ScalarizeVecRes_InregOp(N); break;
case ISD::VSELECT: R = ScalarizeVecRes_VSELECT(N); break;
case ISD::SELECT: R = ScalarizeVecRes_SELECT(N); break;
case ISD::SELECT_CC: R = ScalarizeVecRes_SELECT_CC(N); break;
case ISD::SETCC: R = ScalarizeVecRes_SETCC(N); break;
case ISD::UNDEF: R = ScalarizeVecRes_UNDEF(N); break;
case ISD::VECTOR_SHUFFLE: R = ScalarizeVecRes_VECTOR_SHUFFLE(N); break;
case ISD::IS_FPCLASS: R = ScalarizeVecRes_IS_FPCLASS(N); break;
case ISD::ANY_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
R = ScalarizeVecRes_VecInregOp(N);
break;
case ISD::ABS:
case ISD::ANY_EXTEND:
case ISD::BITREVERSE:
case ISD::BSWAP:
case ISD::CTLZ:
case ISD::CTLZ_ZERO_UNDEF:
case ISD::CTPOP:
case ISD::CTTZ:
case ISD::CTTZ_ZERO_UNDEF:
case ISD::FABS:
case ISD::FCEIL:
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG10:
case ISD::FLOG2:
case ISD::FNEARBYINT:
case ISD::FNEG:
case ISD::FREEZE:
case ISD::ARITH_FENCE:
case ISD::FP_EXTEND:
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
case ISD::SIGN_EXTEND:
case ISD::SINT_TO_FP:
case ISD::TRUNCATE:
case ISD::UINT_TO_FP:
case ISD::ZERO_EXTEND:
case ISD::FCANONICALIZE:
R = ScalarizeVecRes_UnaryOp(N);
break;
case ISD::ADD:
case ISD::AND:
case ISD::FADD:
case ISD::FCOPYSIGN:
case ISD::FDIV:
case ISD::FMUL:
case ISD::FMINNUM:
case ISD::FMAXNUM:
case ISD::FMINNUM_IEEE:
case ISD::FMAXNUM_IEEE:
case ISD::FMINIMUM:
case ISD::FMAXIMUM:
case ISD::SMIN:
case ISD::SMAX:
case ISD::UMIN:
case ISD::UMAX:
case ISD::SADDSAT:
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT:
case ISD::SSHLSAT:
case ISD::USHLSAT:
case ISD::FPOW:
case ISD::FREM:
case ISD::FSUB:
case ISD::MUL:
case ISD::OR:
case ISD::SDIV:
case ISD::SREM:
case ISD::SUB:
case ISD::UDIV:
case ISD::UREM:
case ISD::XOR:
case ISD::SHL:
case ISD::SRA:
case ISD::SRL:
case ISD::ROTL:
case ISD::ROTR:
R = ScalarizeVecRes_BinOp(N);
break;
case ISD::FMA:
case ISD::FSHL:
case ISD::FSHR:
R = ScalarizeVecRes_TernaryOp(N);
break;
#define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \
case ISD::STRICT_##DAGN:
#include "llvm/IR/ConstrainedOps.def"
R = ScalarizeVecRes_StrictFPOp(N);
break;
case ISD::FP_TO_UINT_SAT:
case ISD::FP_TO_SINT_SAT:
R = ScalarizeVecRes_FP_TO_XINT_SAT(N);
break;
case ISD::UADDO:
case ISD::SADDO:
case ISD::USUBO:
case ISD::SSUBO:
case ISD::UMULO:
case ISD::SMULO:
R = ScalarizeVecRes_OverflowOp(N, ResNo);
break;
case ISD::SMULFIX:
case ISD::SMULFIXSAT:
case ISD::UMULFIX:
case ISD::UMULFIXSAT:
case ISD::SDIVFIX:
case ISD::SDIVFIXSAT:
case ISD::UDIVFIX:
case ISD::UDIVFIXSAT:
R = ScalarizeVecRes_FIX(N);
break;
}
if (R.getNode())
SetScalarizedVector(SDValue(N, ResNo), R);
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_BinOp(SDNode *N) {
SDValue LHS = GetScalarizedVector(N->getOperand(0));
SDValue RHS = GetScalarizedVector(N->getOperand(1));
return DAG.getNode(N->getOpcode(), SDLoc(N),
LHS.getValueType(), LHS, RHS, N->getFlags());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_TernaryOp(SDNode *N) {
SDValue Op0 = GetScalarizedVector(N->getOperand(0));
SDValue Op1 = GetScalarizedVector(N->getOperand(1));
SDValue Op2 = GetScalarizedVector(N->getOperand(2));
return DAG.getNode(N->getOpcode(), SDLoc(N), Op0.getValueType(), Op0, Op1,
Op2, N->getFlags());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_FIX(SDNode *N) {
SDValue Op0 = GetScalarizedVector(N->getOperand(0));
SDValue Op1 = GetScalarizedVector(N->getOperand(1));
SDValue Op2 = N->getOperand(2);
return DAG.getNode(N->getOpcode(), SDLoc(N), Op0.getValueType(), Op0, Op1,
Op2, N->getFlags());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_StrictFPOp(SDNode *N) {
EVT VT = N->getValueType(0).getVectorElementType();
unsigned NumOpers = N->getNumOperands();
SDValue Chain = N->getOperand(0);
EVT ValueVTs[] = {VT, MVT::Other};
SDLoc dl(N);
SmallVector<SDValue, 4> Opers(NumOpers);
Opers[0] = Chain;
for (unsigned i = 1; i < NumOpers; ++i) {
SDValue Oper = N->getOperand(i);
EVT OperVT = Oper.getValueType();
if (OperVT.isVector()) {
if (getTypeAction(OperVT) == TargetLowering::TypeScalarizeVector)
Oper = GetScalarizedVector(Oper);
else
Oper = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl,
OperVT.getVectorElementType(), Oper,
DAG.getVectorIdxConstant(0, dl));
}
Opers[i] = Oper;
}
SDValue Result = DAG.getNode(N->getOpcode(), dl, DAG.getVTList(ValueVTs),
Opers, N->getFlags());
ReplaceValueWith(SDValue(N, 1), Result.getValue(1));
return Result;
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_OverflowOp(SDNode *N,
unsigned ResNo) {
SDLoc DL(N);
EVT ResVT = N->getValueType(0);
EVT OvVT = N->getValueType(1);
SDValue ScalarLHS, ScalarRHS;
if (getTypeAction(ResVT) == TargetLowering::TypeScalarizeVector) {
ScalarLHS = GetScalarizedVector(N->getOperand(0));
ScalarRHS = GetScalarizedVector(N->getOperand(1));
} else {
SmallVector<SDValue, 1> ElemsLHS, ElemsRHS;
DAG.ExtractVectorElements(N->getOperand(0), ElemsLHS);
DAG.ExtractVectorElements(N->getOperand(1), ElemsRHS);
ScalarLHS = ElemsLHS[0];
ScalarRHS = ElemsRHS[0];
}
SDVTList ScalarVTs = DAG.getVTList(
ResVT.getVectorElementType(), OvVT.getVectorElementType());
SDNode *ScalarNode = DAG.getNode(
N->getOpcode(), DL, ScalarVTs, ScalarLHS, ScalarRHS).getNode();
ScalarNode->setFlags(N->getFlags());
unsigned OtherNo = 1 - ResNo;
EVT OtherVT = N->getValueType(OtherNo);
if (getTypeAction(OtherVT) == TargetLowering::TypeScalarizeVector) {
SetScalarizedVector(SDValue(N, OtherNo), SDValue(ScalarNode, OtherNo));
} else {
SDValue OtherVal = DAG.getNode(
ISD::SCALAR_TO_VECTOR, DL, OtherVT, SDValue(ScalarNode, OtherNo));
ReplaceValueWith(SDValue(N, OtherNo), OtherVal);
}
return SDValue(ScalarNode, ResNo);
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_MERGE_VALUES(SDNode *N,
unsigned ResNo) {
SDValue Op = DisintegrateMERGE_VALUES(N, ResNo);
return GetScalarizedVector(Op);
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_BITCAST(SDNode *N) {
SDValue Op = N->getOperand(0);
if (Op.getValueType().isVector()
&& Op.getValueType().getVectorNumElements() == 1
&& !isSimpleLegalType(Op.getValueType()))
Op = GetScalarizedVector(Op);
EVT NewVT = N->getValueType(0).getVectorElementType();
return DAG.getNode(ISD::BITCAST, SDLoc(N),
NewVT, Op);
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_BUILD_VECTOR(SDNode *N) {
EVT EltVT = N->getValueType(0).getVectorElementType();
SDValue InOp = N->getOperand(0);
if (EltVT.isInteger())
return DAG.getNode(ISD::TRUNCATE, SDLoc(N), EltVT, InOp);
return InOp;
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_EXTRACT_SUBVECTOR(SDNode *N) {
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(N),
N->getValueType(0).getVectorElementType(),
N->getOperand(0), N->getOperand(1));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_FP_ROUND(SDNode *N) {
SDLoc DL(N);
SDValue Op = N->getOperand(0);
EVT OpVT = Op.getValueType();
if (getTypeAction(OpVT) == TargetLowering::TypeScalarizeVector) {
Op = GetScalarizedVector(Op);
} else {
EVT VT = OpVT.getVectorElementType();
Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Op,
DAG.getVectorIdxConstant(0, DL));
}
return DAG.getNode(ISD::FP_ROUND, DL,
N->getValueType(0).getVectorElementType(), Op,
N->getOperand(1));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_FPOWI(SDNode *N) {
SDValue Op = GetScalarizedVector(N->getOperand(0));
return DAG.getNode(ISD::FPOWI, SDLoc(N),
Op.getValueType(), Op, N->getOperand(1));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_INSERT_VECTOR_ELT(SDNode *N) {
SDValue Op = N->getOperand(1);
EVT EltVT = N->getValueType(0).getVectorElementType();
if (Op.getValueType() != EltVT)
Op = DAG.getNode(ISD::TRUNCATE, SDLoc(N), EltVT, Op);
return Op;
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_LOAD(LoadSDNode *N) {
assert(N->isUnindexed() && "Indexed vector load?");
SDValue Result = DAG.getLoad(
ISD::UNINDEXED, N->getExtensionType(),
N->getValueType(0).getVectorElementType(), SDLoc(N), N->getChain(),
N->getBasePtr(), DAG.getUNDEF(N->getBasePtr().getValueType()),
N->getPointerInfo(), N->getMemoryVT().getVectorElementType(),
N->getOriginalAlign(), N->getMemOperand()->getFlags(), N->getAAInfo());
ReplaceValueWith(SDValue(N, 1), Result.getValue(1));
return Result;
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_UnaryOp(SDNode *N) {
EVT DestVT = N->getValueType(0).getVectorElementType();
SDValue Op = N->getOperand(0);
EVT OpVT = Op.getValueType();
SDLoc DL(N);
if (getTypeAction(OpVT) == TargetLowering::TypeScalarizeVector) {
Op = GetScalarizedVector(Op);
} else {
EVT VT = OpVT.getVectorElementType();
Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Op,
DAG.getVectorIdxConstant(0, DL));
}
return DAG.getNode(N->getOpcode(), SDLoc(N), DestVT, Op, N->getFlags());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_InregOp(SDNode *N) {
EVT EltVT = N->getValueType(0).getVectorElementType();
EVT ExtVT = cast<VTSDNode>(N->getOperand(1))->getVT().getVectorElementType();
SDValue LHS = GetScalarizedVector(N->getOperand(0));
return DAG.getNode(N->getOpcode(), SDLoc(N), EltVT,
LHS, DAG.getValueType(ExtVT));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_VecInregOp(SDNode *N) {
SDLoc DL(N);
SDValue Op = N->getOperand(0);
EVT OpVT = Op.getValueType();
EVT OpEltVT = OpVT.getVectorElementType();
EVT EltVT = N->getValueType(0).getVectorElementType();
if (getTypeAction(OpVT) == TargetLowering::TypeScalarizeVector) {
Op = GetScalarizedVector(Op);
} else {
Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpEltVT, Op,
DAG.getVectorIdxConstant(0, DL));
}
switch (N->getOpcode()) {
case ISD::ANY_EXTEND_VECTOR_INREG:
return DAG.getNode(ISD::ANY_EXTEND, DL, EltVT, Op);
case ISD::SIGN_EXTEND_VECTOR_INREG:
return DAG.getNode(ISD::SIGN_EXTEND, DL, EltVT, Op);
case ISD::ZERO_EXTEND_VECTOR_INREG:
return DAG.getNode(ISD::ZERO_EXTEND, DL, EltVT, Op);
}
llvm_unreachable("Illegal extend_vector_inreg opcode");
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_SCALAR_TO_VECTOR(SDNode *N) {
EVT EltVT = N->getValueType(0).getVectorElementType();
SDValue InOp = N->getOperand(0);
if (InOp.getValueType() != EltVT)
return DAG.getNode(ISD::TRUNCATE, SDLoc(N), EltVT, InOp);
return InOp;
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_VSELECT(SDNode *N) {
SDValue Cond = N->getOperand(0);
EVT OpVT = Cond.getValueType();
SDLoc DL(N);
if (getTypeAction(OpVT) == TargetLowering::TypeScalarizeVector) {
Cond = GetScalarizedVector(Cond);
} else {
EVT VT = OpVT.getVectorElementType();
Cond = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Cond,
DAG.getVectorIdxConstant(0, DL));
}
SDValue LHS = GetScalarizedVector(N->getOperand(1));
TargetLowering::BooleanContent ScalarBool =
TLI.getBooleanContents(false, false);
TargetLowering::BooleanContent VecBool = TLI.getBooleanContents(true, false);
if (TLI.getBooleanContents(false, false) !=
TLI.getBooleanContents(false, true)) {
if (Cond->getOpcode() == ISD::SETCC) {
EVT OpVT = Cond->getOperand(0).getValueType();
ScalarBool = TLI.getBooleanContents(OpVT.getScalarType());
VecBool = TLI.getBooleanContents(OpVT);
} else
ScalarBool = TargetLowering::UndefinedBooleanContent;
}
EVT CondVT = Cond.getValueType();
if (ScalarBool != VecBool) {
switch (ScalarBool) {
case TargetLowering::UndefinedBooleanContent:
break;
case TargetLowering::ZeroOrOneBooleanContent:
assert(VecBool == TargetLowering::UndefinedBooleanContent ||
VecBool == TargetLowering::ZeroOrNegativeOneBooleanContent);
Cond = DAG.getNode(ISD::AND, SDLoc(N), CondVT,
Cond, DAG.getConstant(1, SDLoc(N), CondVT));
break;
case TargetLowering::ZeroOrNegativeOneBooleanContent:
assert(VecBool == TargetLowering::UndefinedBooleanContent ||
VecBool == TargetLowering::ZeroOrOneBooleanContent);
Cond = DAG.getNode(ISD::SIGN_EXTEND_INREG, SDLoc(N), CondVT,
Cond, DAG.getValueType(MVT::i1));
break;
}
}
auto BoolVT = getSetCCResultType(CondVT);
if (BoolVT.bitsLT(CondVT))
Cond = DAG.getNode(ISD::TRUNCATE, SDLoc(N), BoolVT, Cond);
return DAG.getSelect(SDLoc(N),
LHS.getValueType(), Cond, LHS,
GetScalarizedVector(N->getOperand(2)));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_SELECT(SDNode *N) {
SDValue LHS = GetScalarizedVector(N->getOperand(1));
return DAG.getSelect(SDLoc(N),
LHS.getValueType(), N->getOperand(0), LHS,
GetScalarizedVector(N->getOperand(2)));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_SELECT_CC(SDNode *N) {
SDValue LHS = GetScalarizedVector(N->getOperand(2));
return DAG.getNode(ISD::SELECT_CC, SDLoc(N), LHS.getValueType(),
N->getOperand(0), N->getOperand(1),
LHS, GetScalarizedVector(N->getOperand(3)),
N->getOperand(4));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_UNDEF(SDNode *N) {
return DAG.getUNDEF(N->getValueType(0).getVectorElementType());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_VECTOR_SHUFFLE(SDNode *N) {
SDValue Arg = N->getOperand(2).getOperand(0);
if (Arg.isUndef())
return DAG.getUNDEF(N->getValueType(0).getVectorElementType());
unsigned Op = !cast<ConstantSDNode>(Arg)->isZero();
return GetScalarizedVector(N->getOperand(Op));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_FP_TO_XINT_SAT(SDNode *N) {
SDValue Src = N->getOperand(0);
EVT SrcVT = Src.getValueType();
SDLoc dl(N);
if (getTypeAction(SrcVT) == TargetLowering::TypeScalarizeVector)
Src = GetScalarizedVector(Src);
else
Src = DAG.getNode(
ISD::EXTRACT_VECTOR_ELT, dl, SrcVT.getVectorElementType(), Src,
DAG.getConstant(0, dl, TLI.getVectorIdxTy(DAG.getDataLayout())));
EVT DstVT = N->getValueType(0).getVectorElementType();
return DAG.getNode(N->getOpcode(), dl, DstVT, Src, N->getOperand(1));
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_SETCC(SDNode *N) {
assert(N->getValueType(0).isVector() &&
N->getOperand(0).getValueType().isVector() &&
"Operand types must be vectors");
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
EVT OpVT = LHS.getValueType();
EVT NVT = N->getValueType(0).getVectorElementType();
SDLoc DL(N);
if (getTypeAction(OpVT) == TargetLowering::TypeScalarizeVector) {
LHS = GetScalarizedVector(LHS);
RHS = GetScalarizedVector(RHS);
} else {
EVT VT = OpVT.getVectorElementType();
LHS = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, LHS,
DAG.getVectorIdxConstant(0, DL));
RHS = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, RHS,
DAG.getVectorIdxConstant(0, DL));
}
SDValue Res = DAG.getNode(ISD::SETCC, DL, MVT::i1, LHS, RHS,
N->getOperand(2));
ISD::NodeType ExtendCode =
TargetLowering::getExtendForContent(TLI.getBooleanContents(OpVT));
return DAG.getNode(ExtendCode, DL, NVT, Res);
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_IS_FPCLASS(SDNode *N) {
SDLoc DL(N);
SDValue Arg = N->getOperand(0);
SDValue Test = N->getOperand(1);
EVT ArgVT = Arg.getValueType();
EVT ResultVT = N->getValueType(0).getVectorElementType();
if (getTypeAction(ArgVT) == TargetLowering::TypeScalarizeVector) {
Arg = GetScalarizedVector(Arg);
} else {
EVT VT = ArgVT.getVectorElementType();
Arg = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Arg,
DAG.getVectorIdxConstant(0, DL));
}
SDValue Res =
DAG.getNode(ISD::IS_FPCLASS, DL, MVT::i1, {Arg, Test}, N->getFlags());
ISD::NodeType ExtendCode =
TargetLowering::getExtendForContent(TLI.getBooleanContents(ArgVT));
return DAG.getNode(ExtendCode, DL, ResultVT, Res);
}
bool DAGTypeLegalizer::ScalarizeVectorOperand(SDNode *N, unsigned OpNo) {
LLVM_DEBUG(dbgs() << "Scalarize node operand " << OpNo << ": "; N->dump(&DAG);
dbgs() << "\n");
SDValue Res = SDValue();
switch (N->getOpcode()) {
default:
#ifndef NDEBUG
dbgs() << "ScalarizeVectorOperand Op #" << OpNo << ": ";
N->dump(&DAG);
dbgs() << "\n";
#endif
report_fatal_error("Do not know how to scalarize this operator's "
"operand!\n");
case ISD::BITCAST:
Res = ScalarizeVecOp_BITCAST(N);
break;
case ISD::ANY_EXTEND:
case ISD::ZERO_EXTEND:
case ISD::SIGN_EXTEND:
case ISD::TRUNCATE:
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT:
case ISD::SINT_TO_FP:
case ISD::UINT_TO_FP:
Res = ScalarizeVecOp_UnaryOp(N);
break;
case ISD::STRICT_SINT_TO_FP:
case ISD::STRICT_UINT_TO_FP:
case ISD::STRICT_FP_TO_SINT:
case ISD::STRICT_FP_TO_UINT:
Res = ScalarizeVecOp_UnaryOp_StrictFP(N);
break;
case ISD::CONCAT_VECTORS:
Res = ScalarizeVecOp_CONCAT_VECTORS(N);
break;
case ISD::EXTRACT_VECTOR_ELT:
Res = ScalarizeVecOp_EXTRACT_VECTOR_ELT(N);
break;
case ISD::VSELECT:
Res = ScalarizeVecOp_VSELECT(N);
break;
case ISD::SETCC:
Res = ScalarizeVecOp_VSETCC(N);
break;
case ISD::STORE:
Res = ScalarizeVecOp_STORE(cast<StoreSDNode>(N), OpNo);
break;
case ISD::STRICT_FP_ROUND:
Res = ScalarizeVecOp_STRICT_FP_ROUND(N, OpNo);
break;
case ISD::FP_ROUND:
Res = ScalarizeVecOp_FP_ROUND(N, OpNo);
break;
case ISD::STRICT_FP_EXTEND:
Res = ScalarizeVecOp_STRICT_FP_EXTEND(N);
break;
case ISD::FP_EXTEND:
Res = ScalarizeVecOp_FP_EXTEND(N);
break;
case ISD::VECREDUCE_FADD:
case ISD::VECREDUCE_FMUL:
case ISD::VECREDUCE_ADD:
case ISD::VECREDUCE_MUL:
case ISD::VECREDUCE_AND:
case ISD::VECREDUCE_OR:
case ISD::VECREDUCE_XOR:
case ISD::VECREDUCE_SMAX:
case ISD::VECREDUCE_SMIN:
case ISD::VECREDUCE_UMAX:
case ISD::VECREDUCE_UMIN:
case ISD::VECREDUCE_FMAX:
case ISD::VECREDUCE_FMIN:
Res = ScalarizeVecOp_VECREDUCE(N);
break;
case ISD::VECREDUCE_SEQ_FADD:
case ISD::VECREDUCE_SEQ_FMUL:
Res = ScalarizeVecOp_VECREDUCE_SEQ(N);
break;
}
if (!Res.getNode()) return false;
if (Res.getNode() == N)
return true;
assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == 1 &&
"Invalid operand expansion");
ReplaceValueWith(SDValue(N, 0), Res);
return false;
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_BITCAST(SDNode *N) {
SDValue Elt = GetScalarizedVector(N->getOperand(0));
return DAG.getNode(ISD::BITCAST, SDLoc(N),
N->getValueType(0), Elt);
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_UnaryOp(SDNode *N) {
assert(N->getValueType(0).getVectorNumElements() == 1 &&
"Unexpected vector type!");
SDValue Elt = GetScalarizedVector(N->getOperand(0));
SDValue Op = DAG.getNode(N->getOpcode(), SDLoc(N),
N->getValueType(0).getScalarType(), Elt);
return DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), N->getValueType(0), Op);
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_UnaryOp_StrictFP(SDNode *N) {
assert(N->getValueType(0).getVectorNumElements() == 1 &&
"Unexpected vector type!");
SDValue Elt = GetScalarizedVector(N->getOperand(1));
SDValue Res = DAG.getNode(N->getOpcode(), SDLoc(N),
{ N->getValueType(0).getScalarType(), MVT::Other },
{ N->getOperand(0), Elt });
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), N->getValueType(0), Res);
ReplaceValueWith(SDValue(N, 0), Res);
return SDValue();
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_CONCAT_VECTORS(SDNode *N) {
SmallVector<SDValue, 8> Ops(N->getNumOperands());
for (unsigned i = 0, e = N->getNumOperands(); i < e; ++i)
Ops[i] = GetScalarizedVector(N->getOperand(i));
return DAG.getBuildVector(N->getValueType(0), SDLoc(N), Ops);
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_EXTRACT_VECTOR_ELT(SDNode *N) {
EVT VT = N->getValueType(0);
SDValue Res = GetScalarizedVector(N->getOperand(0));
if (Res.getValueType() != VT)
Res = VT.isFloatingPoint()
? DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, Res)
: DAG.getNode(ISD::ANY_EXTEND, SDLoc(N), VT, Res);
return Res;
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_VSELECT(SDNode *N) {
SDValue ScalarCond = GetScalarizedVector(N->getOperand(0));
EVT VT = N->getValueType(0);
return DAG.getNode(ISD::SELECT, SDLoc(N), VT, ScalarCond, N->getOperand(1),
N->getOperand(2));
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_VSETCC(SDNode *N) {
assert(N->getValueType(0).isVector() &&
N->getOperand(0).getValueType().isVector() &&
"Operand types must be vectors");
assert(N->getValueType(0) == MVT::v1i1 && "Expected v1i1 type");
EVT VT = N->getValueType(0);
SDValue LHS = GetScalarizedVector(N->getOperand(0));
SDValue RHS = GetScalarizedVector(N->getOperand(1));
EVT OpVT = N->getOperand(0).getValueType();
EVT NVT = VT.getVectorElementType();
SDLoc DL(N);
SDValue Res = DAG.getNode(ISD::SETCC, DL, MVT::i1, LHS, RHS,
N->getOperand(2));
ISD::NodeType ExtendCode =
TargetLowering::getExtendForContent(TLI.getBooleanContents(OpVT));
Res = DAG.getNode(ExtendCode, DL, NVT, Res);
return DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VT, Res);
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_STORE(StoreSDNode *N, unsigned OpNo){
assert(N->isUnindexed() && "Indexed store of one-element vector?");
assert(OpNo == 1 && "Do not know how to scalarize this operand!");
SDLoc dl(N);
if (N->isTruncatingStore())
return DAG.getTruncStore(
N->getChain(), dl, GetScalarizedVector(N->getOperand(1)),
N->getBasePtr(), N->getPointerInfo(),
N->getMemoryVT().getVectorElementType(), N->getOriginalAlign(),
N->getMemOperand()->getFlags(), N->getAAInfo());
return DAG.getStore(N->getChain(), dl, GetScalarizedVector(N->getOperand(1)),
N->getBasePtr(), N->getPointerInfo(),
N->getOriginalAlign(), N->getMemOperand()->getFlags(),
N->getAAInfo());
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_FP_ROUND(SDNode *N, unsigned OpNo) {
assert(OpNo == 0 && "Wrong operand for scalarization!");
SDValue Elt = GetScalarizedVector(N->getOperand(0));
SDValue Res = DAG.getNode(ISD::FP_ROUND, SDLoc(N),
N->getValueType(0).getVectorElementType(), Elt,
N->getOperand(1));
return DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), N->getValueType(0), Res);
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_STRICT_FP_ROUND(SDNode *N,
unsigned OpNo) {
assert(OpNo == 1 && "Wrong operand for scalarization!");
SDValue Elt = GetScalarizedVector(N->getOperand(1));
SDValue Res = DAG.getNode(ISD::STRICT_FP_ROUND, SDLoc(N),
{ N->getValueType(0).getVectorElementType(),
MVT::Other },
{ N->getOperand(0), Elt, N->getOperand(2) });
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), N->getValueType(0), Res);
ReplaceValueWith(SDValue(N, 0), Res);
return SDValue();
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_FP_EXTEND(SDNode *N) {
SDValue Elt = GetScalarizedVector(N->getOperand(0));
SDValue Res = DAG.getNode(ISD::FP_EXTEND, SDLoc(N),
N->getValueType(0).getVectorElementType(), Elt);
return DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), N->getValueType(0), Res);
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_STRICT_FP_EXTEND(SDNode *N) {
SDValue Elt = GetScalarizedVector(N->getOperand(1));
SDValue Res =
DAG.getNode(ISD::STRICT_FP_EXTEND, SDLoc(N),
{N->getValueType(0).getVectorElementType(), MVT::Other},
{N->getOperand(0), Elt});
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), N->getValueType(0), Res);
ReplaceValueWith(SDValue(N, 0), Res);
return SDValue();
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_VECREDUCE(SDNode *N) {
SDValue Res = GetScalarizedVector(N->getOperand(0));
if (Res.getValueType() != N->getValueType(0))
Res = DAG.getNode(ISD::ANY_EXTEND, SDLoc(N), N->getValueType(0), Res);
return Res;
}
SDValue DAGTypeLegalizer::ScalarizeVecOp_VECREDUCE_SEQ(SDNode *N) {
SDValue AccOp = N->getOperand(0);
SDValue VecOp = N->getOperand(1);
unsigned BaseOpc = ISD::getVecReduceBaseOpcode(N->getOpcode());
SDValue Op = GetScalarizedVector(VecOp);
return DAG.getNode(BaseOpc, SDLoc(N), N->getValueType(0),
AccOp, Op, N->getFlags());
}
void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
LLVM_DEBUG(dbgs() << "Split node result: "; N->dump(&DAG); dbgs() << "\n");
SDValue Lo, Hi;
if (CustomLowerNode(N, N->getValueType(ResNo), true))
return;
switch (N->getOpcode()) {
default:
#ifndef NDEBUG
dbgs() << "SplitVectorResult #" << ResNo << ": ";
N->dump(&DAG);
dbgs() << "\n";
#endif
report_fatal_error("Do not know how to split the result of this "
"operator!\n");
case ISD::MERGE_VALUES: SplitRes_MERGE_VALUES(N, ResNo, Lo, Hi); break;
case ISD::VSELECT:
case ISD::SELECT:
case ISD::VP_MERGE:
case ISD::VP_SELECT: SplitRes_Select(N, Lo, Hi); break;
case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break;
case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break;
case ISD::BITCAST: SplitVecRes_BITCAST(N, Lo, Hi); break;
case ISD::BUILD_VECTOR: SplitVecRes_BUILD_VECTOR(N, Lo, Hi); break;
case ISD::CONCAT_VECTORS: SplitVecRes_CONCAT_VECTORS(N, Lo, Hi); break;
case ISD::EXTRACT_SUBVECTOR: SplitVecRes_EXTRACT_SUBVECTOR(N, Lo, Hi); break;
case ISD::INSERT_SUBVECTOR: SplitVecRes_INSERT_SUBVECTOR(N, Lo, Hi); break;
case ISD::FPOWI: SplitVecRes_FPOWI(N, Lo, Hi); break;
case ISD::FCOPYSIGN: SplitVecRes_FCOPYSIGN(N, Lo, Hi); break;
case ISD::IS_FPCLASS: SplitVecRes_IS_FPCLASS(N, Lo, Hi); break;
case ISD::INSERT_VECTOR_ELT: SplitVecRes_INSERT_VECTOR_ELT(N, Lo, Hi); break;
case ISD::SPLAT_VECTOR:
case ISD::SCALAR_TO_VECTOR:
SplitVecRes_ScalarOp(N, Lo, Hi);
break;
case ISD::STEP_VECTOR:
SplitVecRes_STEP_VECTOR(N, Lo, Hi);
break;
case ISD::SIGN_EXTEND_INREG: SplitVecRes_InregOp(N, Lo, Hi); break;
case ISD::LOAD:
SplitVecRes_LOAD(cast<LoadSDNode>(N), Lo, Hi);
break;
case ISD::VP_LOAD:
SplitVecRes_VP_LOAD(cast<VPLoadSDNode>(N), Lo, Hi);
break;
case ISD::MLOAD:
SplitVecRes_MLOAD(cast<MaskedLoadSDNode>(N), Lo, Hi);
break;
case ISD::MGATHER:
case ISD::VP_GATHER:
SplitVecRes_Gather(cast<MemSDNode>(N), Lo, Hi, true);
break;
case ISD::SETCC:
case ISD::VP_SETCC:
SplitVecRes_SETCC(N, Lo, Hi);
break;
case ISD::VECTOR_REVERSE:
SplitVecRes_VECTOR_REVERSE(N, Lo, Hi);
break;
case ISD::VECTOR_SHUFFLE:
SplitVecRes_VECTOR_SHUFFLE(cast<ShuffleVectorSDNode>(N), Lo, Hi);
break;
case ISD::VECTOR_SPLICE:
SplitVecRes_VECTOR_SPLICE(N, Lo, Hi);
break;
case ISD::VAARG:
SplitVecRes_VAARG(N, Lo, Hi);
break;
case ISD::ANY_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
SplitVecRes_ExtVecInRegOp(N, Lo, Hi);
break;
case ISD::ABS:
case ISD::BITREVERSE:
case ISD::BSWAP:
case ISD::CTLZ:
case ISD::CTTZ:
case ISD::CTLZ_ZERO_UNDEF:
case ISD::CTTZ_ZERO_UNDEF:
case ISD::CTPOP:
case ISD::FABS:
case ISD::FCEIL:
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG10:
case ISD::FLOG2:
case ISD::FNEARBYINT:
case ISD::FNEG: case ISD::VP_FNEG:
case ISD::FREEZE:
case ISD::ARITH_FENCE:
case ISD::FP_EXTEND:
case ISD::VP_FP_EXTEND:
case ISD::FP_ROUND:
case ISD::VP_FP_ROUND:
case ISD::FP_TO_SINT:
case ISD::VP_FPTOSI:
case ISD::FP_TO_UINT:
case ISD::VP_FPTOUI:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
case ISD::SINT_TO_FP:
case ISD::VP_SITOFP:
case ISD::TRUNCATE:
case ISD::VP_TRUNCATE:
case ISD::UINT_TO_FP:
case ISD::VP_UITOFP:
case ISD::FCANONICALIZE:
SplitVecRes_UnaryOp(N, Lo, Hi);
break;
case ISD::ANY_EXTEND:
case ISD::SIGN_EXTEND:
case ISD::ZERO_EXTEND:
case ISD::VP_SIGN_EXTEND:
case ISD::VP_ZERO_EXTEND:
SplitVecRes_ExtendOp(N, Lo, Hi);
break;
case ISD::ADD: case ISD::VP_ADD:
case ISD::SUB: case ISD::VP_SUB:
case ISD::MUL: case ISD::VP_MUL:
case ISD::MULHS:
case ISD::MULHU:
case ISD::FADD: case ISD::VP_FADD:
case ISD::FSUB: case ISD::VP_FSUB:
case ISD::FMUL: case ISD::VP_FMUL:
case ISD::FMINNUM:
case ISD::FMAXNUM:
case ISD::FMINIMUM:
case ISD::FMAXIMUM:
case ISD::SDIV: case ISD::VP_SDIV:
case ISD::UDIV: case ISD::VP_UDIV:
case ISD::FDIV: case ISD::VP_FDIV:
case ISD::FPOW:
case ISD::AND: case ISD::VP_AND:
case ISD::OR: case ISD::VP_OR:
case ISD::XOR: case ISD::VP_XOR:
case ISD::SHL: case ISD::VP_SHL:
case ISD::SRA: case ISD::VP_ASHR:
case ISD::SRL: case ISD::VP_LSHR:
case ISD::UREM: case ISD::VP_UREM:
case ISD::SREM: case ISD::VP_SREM:
case ISD::FREM: case ISD::VP_FREM:
case ISD::SMIN:
case ISD::SMAX:
case ISD::UMIN:
case ISD::UMAX:
case ISD::SADDSAT:
case ISD::UADDSAT:
case ISD::SSUBSAT:
case ISD::USUBSAT:
case ISD::SSHLSAT:
case ISD::USHLSAT:
case ISD::ROTL:
case ISD::ROTR:
SplitVecRes_BinOp(N, Lo, Hi);
break;
case ISD::FMA: case ISD::VP_FMA:
case ISD::FSHL:
case ISD::FSHR:
SplitVecRes_TernaryOp(N, Lo, Hi);
break;
#define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \
case ISD::STRICT_##DAGN:
#include "llvm/IR/ConstrainedOps.def"
SplitVecRes_StrictFPOp(N, Lo, Hi);
break;
case ISD::FP_TO_UINT_SAT:
case ISD::FP_TO_SINT_SAT:
SplitVecRes_FP_TO_XINT_SAT(N, Lo, Hi);
break;
case ISD::UADDO:
case ISD::SADDO:
case ISD::USUBO:
case ISD::SSUBO:
case ISD::UMULO:
case ISD::SMULO:
SplitVecRes_OverflowOp(N, ResNo, Lo, Hi);
break;
case ISD::SMULFIX:
case ISD::SMULFIXSAT:
case ISD::UMULFIX:
case ISD::UMULFIXSAT:
case ISD::SDIVFIX:
case ISD::SDIVFIXSAT:
case ISD::UDIVFIX:
case ISD::UDIVFIXSAT:
SplitVecRes_FIX(N, Lo, Hi);
break;
}
if (Lo.getNode())
SetSplitVector(SDValue(N, ResNo), Lo, Hi);
}
void DAGTypeLegalizer::IncrementPointer(MemSDNode *N, EVT MemVT,
MachinePointerInfo &MPI, SDValue &Ptr,
uint64_t *ScaledOffset) {
SDLoc DL(N);
unsigned IncrementSize = MemVT.getSizeInBits().getKnownMinSize() / 8;
if (MemVT.isScalableVector()) {
SDNodeFlags Flags;
SDValue BytesIncrement = DAG.getVScale(
DL, Ptr.getValueType(),
APInt(Ptr.getValueSizeInBits().getFixedSize(), IncrementSize));
MPI = MachinePointerInfo(N->getPointerInfo().getAddrSpace());
Flags.setNoUnsignedWrap(true);
if (ScaledOffset)
*ScaledOffset += IncrementSize;
Ptr = DAG.getNode(ISD::ADD, DL, Ptr.getValueType(), Ptr, BytesIncrement,
Flags);
} else {
MPI = N->getPointerInfo().getWithOffset(IncrementSize);
Ptr = DAG.getObjectPtrOffset(DL, Ptr, TypeSize::Fixed(IncrementSize));
}
}
std::pair<SDValue, SDValue> DAGTypeLegalizer::SplitMask(SDValue Mask) {
return SplitMask(Mask, SDLoc(Mask));
}
std::pair<SDValue, SDValue> DAGTypeLegalizer::SplitMask(SDValue Mask,
const SDLoc &DL) {
SDValue MaskLo, MaskHi;
EVT MaskVT = Mask.getValueType();
if (getTypeAction(MaskVT) == TargetLowering::TypeSplitVector)
GetSplitVector(Mask, MaskLo, MaskHi);
else
std::tie(MaskLo, MaskHi) = DAG.SplitVector(Mask, DL);
return std::make_pair(MaskLo, MaskHi);
}
void DAGTypeLegalizer::SplitVecRes_BinOp(SDNode *N, SDValue &Lo, SDValue &Hi) {
SDValue LHSLo, LHSHi;
GetSplitVector(N->getOperand(0), LHSLo, LHSHi);
SDValue RHSLo, RHSHi;
GetSplitVector(N->getOperand(1), RHSLo, RHSHi);
SDLoc dl(N);
const SDNodeFlags Flags = N->getFlags();
unsigned Opcode = N->getOpcode();
if (N->getNumOperands() == 2) {
Lo = DAG.getNode(Opcode, dl, LHSLo.getValueType(), LHSLo, RHSLo, Flags);
Hi = DAG.getNode(Opcode, dl, LHSHi.getValueType(), LHSHi, RHSHi, Flags);
return;
}
assert(N->getNumOperands() == 4 && "Unexpected number of operands!");
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue MaskLo, MaskHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(2));
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(3), N->getValueType(0), dl);
Lo = DAG.getNode(Opcode, dl, LHSLo.getValueType(),
{LHSLo, RHSLo, MaskLo, EVLLo}, Flags);
Hi = DAG.getNode(Opcode, dl, LHSHi.getValueType(),
{LHSHi, RHSHi, MaskHi, EVLHi}, Flags);
}
void DAGTypeLegalizer::SplitVecRes_TernaryOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue Op0Lo, Op0Hi;
GetSplitVector(N->getOperand(0), Op0Lo, Op0Hi);
SDValue Op1Lo, Op1Hi;
GetSplitVector(N->getOperand(1), Op1Lo, Op1Hi);
SDValue Op2Lo, Op2Hi;
GetSplitVector(N->getOperand(2), Op2Lo, Op2Hi);
SDLoc dl(N);
const SDNodeFlags Flags = N->getFlags();
unsigned Opcode = N->getOpcode();
if (N->getNumOperands() == 3) {
Lo = DAG.getNode(Opcode, dl, Op0Lo.getValueType(), Op0Lo, Op1Lo, Op2Lo, Flags);
Hi = DAG.getNode(Opcode, dl, Op0Hi.getValueType(), Op0Hi, Op1Hi, Op2Hi, Flags);
return;
}
assert(N->getNumOperands() == 5 && "Unexpected number of operands!");
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue MaskLo, MaskHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(3));
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(4), N->getValueType(0), dl);
Lo = DAG.getNode(Opcode, dl, Op0Lo.getValueType(),
{Op0Lo, Op1Lo, Op2Lo, MaskLo, EVLLo}, Flags);
Hi = DAG.getNode(Opcode, dl, Op0Hi.getValueType(),
{Op0Hi, Op1Hi, Op2Hi, MaskHi, EVLHi}, Flags);
}
void DAGTypeLegalizer::SplitVecRes_FIX(SDNode *N, SDValue &Lo, SDValue &Hi) {
SDValue LHSLo, LHSHi;
GetSplitVector(N->getOperand(0), LHSLo, LHSHi);
SDValue RHSLo, RHSHi;
GetSplitVector(N->getOperand(1), RHSLo, RHSHi);
SDLoc dl(N);
SDValue Op2 = N->getOperand(2);
unsigned Opcode = N->getOpcode();
Lo = DAG.getNode(Opcode, dl, LHSLo.getValueType(), LHSLo, RHSLo, Op2,
N->getFlags());
Hi = DAG.getNode(Opcode, dl, LHSHi.getValueType(), LHSHi, RHSHi, Op2,
N->getFlags());
}
void DAGTypeLegalizer::SplitVecRes_BITCAST(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
SDLoc dl(N);
SDValue InOp = N->getOperand(0);
EVT InVT = InOp.getValueType();
switch (getTypeAction(InVT)) {
case TargetLowering::TypeLegal:
case TargetLowering::TypePromoteInteger:
case TargetLowering::TypePromoteFloat:
case TargetLowering::TypeSoftPromoteHalf:
case TargetLowering::TypeSoftenFloat:
case TargetLowering::TypeScalarizeVector:
case TargetLowering::TypeWidenVector:
break;
case TargetLowering::TypeExpandInteger:
case TargetLowering::TypeExpandFloat:
if (LoVT == HiVT) {
GetExpandedOp(InOp, Lo, Hi);
if (DAG.getDataLayout().isBigEndian())
std::swap(Lo, Hi);
Lo = DAG.getNode(ISD::BITCAST, dl, LoVT, Lo);
Hi = DAG.getNode(ISD::BITCAST, dl, HiVT, Hi);
return;
}
break;
case TargetLowering::TypeSplitVector:
GetSplitVector(InOp, Lo, Hi);
Lo = DAG.getNode(ISD::BITCAST, dl, LoVT, Lo);
Hi = DAG.getNode(ISD::BITCAST, dl, HiVT, Hi);
return;
case TargetLowering::TypeScalarizeScalableVector:
report_fatal_error("Scalarization of scalable vectors is not supported.");
}
EVT LoIntVT = EVT::getIntegerVT(*DAG.getContext(), LoVT.getSizeInBits());
EVT HiIntVT = EVT::getIntegerVT(*DAG.getContext(), HiVT.getSizeInBits());
if (DAG.getDataLayout().isBigEndian())
std::swap(LoIntVT, HiIntVT);
SplitInteger(BitConvertToInteger(InOp), LoIntVT, HiIntVT, Lo, Hi);
if (DAG.getDataLayout().isBigEndian())
std::swap(Lo, Hi);
Lo = DAG.getNode(ISD::BITCAST, dl, LoVT, Lo);
Hi = DAG.getNode(ISD::BITCAST, dl, HiVT, Hi);
}
void DAGTypeLegalizer::SplitVecRes_BUILD_VECTOR(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT LoVT, HiVT;
SDLoc dl(N);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
unsigned LoNumElts = LoVT.getVectorNumElements();
SmallVector<SDValue, 8> LoOps(N->op_begin(), N->op_begin()+LoNumElts);
Lo = DAG.getBuildVector(LoVT, dl, LoOps);
SmallVector<SDValue, 8> HiOps(N->op_begin()+LoNumElts, N->op_end());
Hi = DAG.getBuildVector(HiVT, dl, HiOps);
}
void DAGTypeLegalizer::SplitVecRes_CONCAT_VECTORS(SDNode *N, SDValue &Lo,
SDValue &Hi) {
assert(!(N->getNumOperands() & 1) && "Unsupported CONCAT_VECTORS");
SDLoc dl(N);
unsigned NumSubvectors = N->getNumOperands() / 2;
if (NumSubvectors == 1) {
Lo = N->getOperand(0);
Hi = N->getOperand(1);
return;
}
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
SmallVector<SDValue, 8> LoOps(N->op_begin(), N->op_begin()+NumSubvectors);
Lo = DAG.getNode(ISD::CONCAT_VECTORS, dl, LoVT, LoOps);
SmallVector<SDValue, 8> HiOps(N->op_begin()+NumSubvectors, N->op_end());
Hi = DAG.getNode(ISD::CONCAT_VECTORS, dl, HiVT, HiOps);
}
void DAGTypeLegalizer::SplitVecRes_EXTRACT_SUBVECTOR(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue Vec = N->getOperand(0);
SDValue Idx = N->getOperand(1);
SDLoc dl(N);
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
Lo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, LoVT, Vec, Idx);
uint64_t IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
Hi = DAG.getNode(
ISD::EXTRACT_SUBVECTOR, dl, HiVT, Vec,
DAG.getVectorIdxConstant(IdxVal + LoVT.getVectorMinNumElements(), dl));
}
void DAGTypeLegalizer::SplitVecRes_INSERT_SUBVECTOR(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue Vec = N->getOperand(0);
SDValue SubVec = N->getOperand(1);
SDValue Idx = N->getOperand(2);
SDLoc dl(N);
GetSplitVector(Vec, Lo, Hi);
EVT VecVT = Vec.getValueType();
EVT LoVT = Lo.getValueType();
EVT SubVecVT = SubVec.getValueType();
unsigned VecElems = VecVT.getVectorMinNumElements();
unsigned SubElems = SubVecVT.getVectorMinNumElements();
unsigned LoElems = LoVT.getVectorMinNumElements();
unsigned IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
if (IdxVal + SubElems <= LoElems) {
Lo = DAG.getNode(ISD::INSERT_SUBVECTOR, dl, LoVT, Lo, SubVec, Idx);
return;
}
if (VecVT.isScalableVector() == SubVecVT.isScalableVector() &&
IdxVal >= LoElems && IdxVal + SubElems <= VecElems) {
Hi = DAG.getNode(ISD::INSERT_SUBVECTOR, dl, Hi.getValueType(), Hi, SubVec,
DAG.getVectorIdxConstant(IdxVal - LoElems, dl));
return;
}
Align SmallestAlign = DAG.getReducedAlign(VecVT, false);
SDValue StackPtr =
DAG.CreateStackTemporary(VecVT.getStoreSize(), SmallestAlign);
auto &MF = DAG.getMachineFunction();
auto FrameIndex = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo,
SmallestAlign);
SDValue SubVecPtr =
TLI.getVectorSubVecPointer(DAG, StackPtr, VecVT, SubVecVT, Idx);
Store = DAG.getStore(Store, dl, SubVec, SubVecPtr,
MachinePointerInfo::getUnknownStack(MF));
Lo = DAG.getLoad(Lo.getValueType(), dl, Store, StackPtr, PtrInfo,
SmallestAlign);
auto *Load = cast<LoadSDNode>(Lo);
MachinePointerInfo MPI = Load->getPointerInfo();
IncrementPointer(Load, LoVT, MPI, StackPtr);
Hi = DAG.getLoad(Hi.getValueType(), dl, Store, StackPtr, MPI, SmallestAlign);
}
void DAGTypeLegalizer::SplitVecRes_FPOWI(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDLoc dl(N);
GetSplitVector(N->getOperand(0), Lo, Hi);
Lo = DAG.getNode(ISD::FPOWI, dl, Lo.getValueType(), Lo, N->getOperand(1));
Hi = DAG.getNode(ISD::FPOWI, dl, Hi.getValueType(), Hi, N->getOperand(1));
}
void DAGTypeLegalizer::SplitVecRes_FCOPYSIGN(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue LHSLo, LHSHi;
GetSplitVector(N->getOperand(0), LHSLo, LHSHi);
SDLoc DL(N);
SDValue RHSLo, RHSHi;
SDValue RHS = N->getOperand(1);
EVT RHSVT = RHS.getValueType();
if (getTypeAction(RHSVT) == TargetLowering::TypeSplitVector)
GetSplitVector(RHS, RHSLo, RHSHi);
else
std::tie(RHSLo, RHSHi) = DAG.SplitVector(RHS, SDLoc(RHS));
Lo = DAG.getNode(ISD::FCOPYSIGN, DL, LHSLo.getValueType(), LHSLo, RHSLo);
Hi = DAG.getNode(ISD::FCOPYSIGN, DL, LHSHi.getValueType(), LHSHi, RHSHi);
}
void DAGTypeLegalizer::SplitVecRes_IS_FPCLASS(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDLoc DL(N);
SDValue ArgLo, ArgHi;
SDValue Test = N->getOperand(1);
GetSplitVector(N->getOperand(0), ArgLo, ArgHi);
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
Lo = DAG.getNode(ISD::IS_FPCLASS, DL, LoVT, ArgLo, Test, N->getFlags());
Hi = DAG.getNode(ISD::IS_FPCLASS, DL, HiVT, ArgHi, Test, N->getFlags());
}
void DAGTypeLegalizer::SplitVecRes_InregOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue LHSLo, LHSHi;
GetSplitVector(N->getOperand(0), LHSLo, LHSHi);
SDLoc dl(N);
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) =
DAG.GetSplitDestVTs(cast<VTSDNode>(N->getOperand(1))->getVT());
Lo = DAG.getNode(N->getOpcode(), dl, LHSLo.getValueType(), LHSLo,
DAG.getValueType(LoVT));
Hi = DAG.getNode(N->getOpcode(), dl, LHSHi.getValueType(), LHSHi,
DAG.getValueType(HiVT));
}
void DAGTypeLegalizer::SplitVecRes_ExtVecInRegOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
unsigned Opcode = N->getOpcode();
SDValue N0 = N->getOperand(0);
SDLoc dl(N);
SDValue InLo, InHi;
if (getTypeAction(N0.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(N0, InLo, InHi);
else
std::tie(InLo, InHi) = DAG.SplitVectorOperand(N, 0);
EVT InLoVT = InLo.getValueType();
unsigned InNumElements = InLoVT.getVectorNumElements();
EVT OutLoVT, OutHiVT;
std::tie(OutLoVT, OutHiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
unsigned OutNumElements = OutLoVT.getVectorNumElements();
assert((2 * OutNumElements) <= InNumElements &&
"Illegal extend vector in reg split");
SmallVector<int, 8> SplitHi(InNumElements, -1);
for (unsigned i = 0; i != OutNumElements; ++i)
SplitHi[i] = i + OutNumElements;
InHi = DAG.getVectorShuffle(InLoVT, dl, InLo, DAG.getUNDEF(InLoVT), SplitHi);
Lo = DAG.getNode(Opcode, dl, OutLoVT, InLo);
Hi = DAG.getNode(Opcode, dl, OutHiVT, InHi);
}
void DAGTypeLegalizer::SplitVecRes_StrictFPOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
unsigned NumOps = N->getNumOperands();
SDValue Chain = N->getOperand(0);
EVT LoVT, HiVT;
SDLoc dl(N);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
SmallVector<SDValue, 4> OpsLo(NumOps);
SmallVector<SDValue, 4> OpsHi(NumOps);
OpsLo[0] = Chain;
OpsHi[0] = Chain;
for (unsigned i = 1; i < NumOps; ++i) {
SDValue Op = N->getOperand(i);
SDValue OpLo = Op;
SDValue OpHi = Op;
EVT InVT = Op.getValueType();
if (InVT.isVector()) {
if (getTypeAction(InVT) == TargetLowering::TypeSplitVector)
GetSplitVector(Op, OpLo, OpHi);
else
std::tie(OpLo, OpHi) = DAG.SplitVectorOperand(N, i);
}
OpsLo[i] = OpLo;
OpsHi[i] = OpHi;
}
EVT LoValueVTs[] = {LoVT, MVT::Other};
EVT HiValueVTs[] = {HiVT, MVT::Other};
Lo = DAG.getNode(N->getOpcode(), dl, DAG.getVTList(LoValueVTs), OpsLo,
N->getFlags());
Hi = DAG.getNode(N->getOpcode(), dl, DAG.getVTList(HiValueVTs), OpsHi,
N->getFlags());
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
Lo.getValue(1), Hi.getValue(1));
ReplaceValueWith(SDValue(N, 1), Chain);
}
SDValue DAGTypeLegalizer::UnrollVectorOp_StrictFP(SDNode *N, unsigned ResNE) {
SDValue Chain = N->getOperand(0);
EVT VT = N->getValueType(0);
unsigned NE = VT.getVectorNumElements();
EVT EltVT = VT.getVectorElementType();
SDLoc dl(N);
SmallVector<SDValue, 8> Scalars;
SmallVector<SDValue, 4> Operands(N->getNumOperands());
if (ResNE == 0)
ResNE = NE;
else if (NE > ResNE)
NE = ResNE;
EVT ChainVTs[] = {EltVT, MVT::Other};
SmallVector<SDValue, 8> Chains;
unsigned i;
for (i = 0; i != NE; ++i) {
Operands[0] = Chain;
for (unsigned j = 1, e = N->getNumOperands(); j != e; ++j) {
SDValue Operand = N->getOperand(j);
EVT OperandVT = Operand.getValueType();
if (OperandVT.isVector()) {
EVT OperandEltVT = OperandVT.getVectorElementType();
Operands[j] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, OperandEltVT,
Operand, DAG.getVectorIdxConstant(i, dl));
} else {
Operands[j] = Operand;
}
}
SDValue Scalar = DAG.getNode(N->getOpcode(), dl, ChainVTs, Operands);
Scalar.getNode()->setFlags(N->getFlags());
Scalars.push_back(Scalar);
Chains.push_back(Scalar.getValue(1));
}
for (; i < ResNE; ++i)
Scalars.push_back(DAG.getUNDEF(EltVT));
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Chains);
ReplaceValueWith(SDValue(N, 1), Chain);
EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, ResNE);
return DAG.getBuildVector(VecVT, dl, Scalars);
}
void DAGTypeLegalizer::SplitVecRes_OverflowOp(SDNode *N, unsigned ResNo,
SDValue &Lo, SDValue &Hi) {
SDLoc dl(N);
EVT ResVT = N->getValueType(0);
EVT OvVT = N->getValueType(1);
EVT LoResVT, HiResVT, LoOvVT, HiOvVT;
std::tie(LoResVT, HiResVT) = DAG.GetSplitDestVTs(ResVT);
std::tie(LoOvVT, HiOvVT) = DAG.GetSplitDestVTs(OvVT);
SDValue LoLHS, HiLHS, LoRHS, HiRHS;
if (getTypeAction(ResVT) == TargetLowering::TypeSplitVector) {
GetSplitVector(N->getOperand(0), LoLHS, HiLHS);
GetSplitVector(N->getOperand(1), LoRHS, HiRHS);
} else {
std::tie(LoLHS, HiLHS) = DAG.SplitVectorOperand(N, 0);
std::tie(LoRHS, HiRHS) = DAG.SplitVectorOperand(N, 1);
}
unsigned Opcode = N->getOpcode();
SDVTList LoVTs = DAG.getVTList(LoResVT, LoOvVT);
SDVTList HiVTs = DAG.getVTList(HiResVT, HiOvVT);
SDNode *LoNode = DAG.getNode(Opcode, dl, LoVTs, LoLHS, LoRHS).getNode();
SDNode *HiNode = DAG.getNode(Opcode, dl, HiVTs, HiLHS, HiRHS).getNode();
LoNode->setFlags(N->getFlags());
HiNode->setFlags(N->getFlags());
Lo = SDValue(LoNode, ResNo);
Hi = SDValue(HiNode, ResNo);
unsigned OtherNo = 1 - ResNo;
EVT OtherVT = N->getValueType(OtherNo);
if (getTypeAction(OtherVT) == TargetLowering::TypeSplitVector) {
SetSplitVector(SDValue(N, OtherNo),
SDValue(LoNode, OtherNo), SDValue(HiNode, OtherNo));
} else {
SDValue OtherVal = DAG.getNode(
ISD::CONCAT_VECTORS, dl, OtherVT,
SDValue(LoNode, OtherNo), SDValue(HiNode, OtherNo));
ReplaceValueWith(SDValue(N, OtherNo), OtherVal);
}
}
void DAGTypeLegalizer::SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue Vec = N->getOperand(0);
SDValue Elt = N->getOperand(1);
SDValue Idx = N->getOperand(2);
SDLoc dl(N);
GetSplitVector(Vec, Lo, Hi);
if (ConstantSDNode *CIdx = dyn_cast<ConstantSDNode>(Idx)) {
unsigned IdxVal = CIdx->getZExtValue();
unsigned LoNumElts = Lo.getValueType().getVectorMinNumElements();
if (IdxVal < LoNumElts) {
Lo = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl,
Lo.getValueType(), Lo, Elt, Idx);
return;
} else if (!Vec.getValueType().isScalableVector()) {
Hi = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, Hi.getValueType(), Hi, Elt,
DAG.getVectorIdxConstant(IdxVal - LoNumElts, dl));
return;
}
}
if (CustomLowerNode(N, N->getValueType(0), true))
return;
EVT VecVT = Vec.getValueType();
EVT EltVT = VecVT.getVectorElementType();
if (VecVT.getScalarSizeInBits() < 8) {
EltVT = MVT::i8;
VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT,
VecVT.getVectorElementCount());
Vec = DAG.getNode(ISD::ANY_EXTEND, dl, VecVT, Vec);
if (EltVT.bitsGT(Elt.getValueType()))
Elt = DAG.getNode(ISD::ANY_EXTEND, dl, EltVT, Elt);
}
Align SmallestAlign = DAG.getReducedAlign(VecVT, false);
SDValue StackPtr =
DAG.CreateStackTemporary(VecVT.getStoreSize(), SmallestAlign);
auto &MF = DAG.getMachineFunction();
auto FrameIndex = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo,
SmallestAlign);
SDValue EltPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx);
Store = DAG.getTruncStore(
Store, dl, Elt, EltPtr, MachinePointerInfo::getUnknownStack(MF), EltVT,
commonAlignment(SmallestAlign,
EltVT.getFixedSizeInBits() / 8));
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(VecVT);
Lo = DAG.getLoad(LoVT, dl, Store, StackPtr, PtrInfo, SmallestAlign);
auto Load = cast<LoadSDNode>(Lo);
MachinePointerInfo MPI = Load->getPointerInfo();
IncrementPointer(Load, LoVT, MPI, StackPtr);
Hi = DAG.getLoad(HiVT, dl, Store, StackPtr, MPI, SmallestAlign);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
if (LoVT != Lo.getValueType())
Lo = DAG.getNode(ISD::TRUNCATE, dl, LoVT, Lo);
if (HiVT != Hi.getValueType())
Hi = DAG.getNode(ISD::TRUNCATE, dl, HiVT, Hi);
}
void DAGTypeLegalizer::SplitVecRes_STEP_VECTOR(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT LoVT, HiVT;
SDLoc dl(N);
assert(N->getValueType(0).isScalableVector() &&
"Only scalable vectors are supported for STEP_VECTOR");
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
SDValue Step = N->getOperand(0);
Lo = DAG.getNode(ISD::STEP_VECTOR, dl, LoVT, Step);
EVT EltVT = Step.getValueType();
APInt StepVal = cast<ConstantSDNode>(Step)->getAPIntValue();
SDValue StartOfHi =
DAG.getVScale(dl, EltVT, StepVal * LoVT.getVectorMinNumElements());
StartOfHi = DAG.getSExtOrTrunc(StartOfHi, dl, HiVT.getVectorElementType());
StartOfHi = DAG.getNode(ISD::SPLAT_VECTOR, dl, HiVT, StartOfHi);
Hi = DAG.getNode(ISD::STEP_VECTOR, dl, HiVT, Step);
Hi = DAG.getNode(ISD::ADD, dl, HiVT, Hi, StartOfHi);
}
void DAGTypeLegalizer::SplitVecRes_ScalarOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT LoVT, HiVT;
SDLoc dl(N);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
Lo = DAG.getNode(N->getOpcode(), dl, LoVT, N->getOperand(0));
if (N->getOpcode() == ISD::SCALAR_TO_VECTOR) {
Hi = DAG.getUNDEF(HiVT);
} else {
assert(N->getOpcode() == ISD::SPLAT_VECTOR && "Unexpected opcode");
Hi = Lo;
}
}
void DAGTypeLegalizer::SplitVecRes_LOAD(LoadSDNode *LD, SDValue &Lo,
SDValue &Hi) {
assert(ISD::isUNINDEXEDLoad(LD) && "Indexed load during type legalization!");
EVT LoVT, HiVT;
SDLoc dl(LD);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(LD->getValueType(0));
ISD::LoadExtType ExtType = LD->getExtensionType();
SDValue Ch = LD->getChain();
SDValue Ptr = LD->getBasePtr();
SDValue Offset = DAG.getUNDEF(Ptr.getValueType());
EVT MemoryVT = LD->getMemoryVT();
MachineMemOperand::Flags MMOFlags = LD->getMemOperand()->getFlags();
AAMDNodes AAInfo = LD->getAAInfo();
EVT LoMemVT, HiMemVT;
std::tie(LoMemVT, HiMemVT) = DAG.GetSplitDestVTs(MemoryVT);
if (!LoMemVT.isByteSized() || !HiMemVT.isByteSized()) {
SDValue Value, NewChain;
std::tie(Value, NewChain) = TLI.scalarizeVectorLoad(LD, DAG);
std::tie(Lo, Hi) = DAG.SplitVector(Value, dl);
ReplaceValueWith(SDValue(LD, 1), NewChain);
return;
}
Lo = DAG.getLoad(ISD::UNINDEXED, ExtType, LoVT, dl, Ch, Ptr, Offset,
LD->getPointerInfo(), LoMemVT, LD->getOriginalAlign(),
MMOFlags, AAInfo);
MachinePointerInfo MPI;
IncrementPointer(LD, LoMemVT, MPI, Ptr);
Hi = DAG.getLoad(ISD::UNINDEXED, ExtType, HiVT, dl, Ch, Ptr, Offset, MPI,
HiMemVT, LD->getOriginalAlign(), MMOFlags, AAInfo);
Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1),
Hi.getValue(1));
ReplaceValueWith(SDValue(LD, 1), Ch);
}
void DAGTypeLegalizer::SplitVecRes_VP_LOAD(VPLoadSDNode *LD, SDValue &Lo,
SDValue &Hi) {
assert(LD->isUnindexed() && "Indexed VP load during type legalization!");
EVT LoVT, HiVT;
SDLoc dl(LD);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(LD->getValueType(0));
ISD::LoadExtType ExtType = LD->getExtensionType();
SDValue Ch = LD->getChain();
SDValue Ptr = LD->getBasePtr();
SDValue Offset = LD->getOffset();
assert(Offset.isUndef() && "Unexpected indexed variable-length load offset");
Align Alignment = LD->getOriginalAlign();
SDValue Mask = LD->getMask();
SDValue EVL = LD->getVectorLength();
EVT MemoryVT = LD->getMemoryVT();
EVT LoMemVT, HiMemVT;
bool HiIsEmpty = false;
std::tie(LoMemVT, HiMemVT) =
DAG.GetDependentSplitDestVTs(MemoryVT, LoVT, &HiIsEmpty);
SDValue MaskLo, MaskHi;
if (Mask.getOpcode() == ISD::SETCC) {
SplitVecRes_SETCC(Mask.getNode(), MaskLo, MaskHi);
} else {
if (getTypeAction(Mask.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Mask, MaskLo, MaskHi);
else
std::tie(MaskLo, MaskHi) = DAG.SplitVector(Mask, dl);
}
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) = DAG.SplitEVL(EVL, LD->getValueType(0), dl);
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
LD->getPointerInfo(), MachineMemOperand::MOLoad,
MemoryLocation::UnknownSize, Alignment, LD->getAAInfo(), LD->getRanges());
Lo =
DAG.getLoadVP(LD->getAddressingMode(), ExtType, LoVT, dl, Ch, Ptr, Offset,
MaskLo, EVLLo, LoMemVT, MMO, LD->isExpandingLoad());
if (HiIsEmpty) {
Hi = Lo;
} else {
Ptr = TLI.IncrementMemoryAddress(Ptr, MaskLo, dl, LoMemVT, DAG,
LD->isExpandingLoad());
MachinePointerInfo MPI;
if (LoMemVT.isScalableVector())
MPI = MachinePointerInfo(LD->getPointerInfo().getAddrSpace());
else
MPI = LD->getPointerInfo().getWithOffset(
LoMemVT.getStoreSize().getFixedSize());
MMO = DAG.getMachineFunction().getMachineMemOperand(
MPI, MachineMemOperand::MOLoad, MemoryLocation::UnknownSize, Alignment,
LD->getAAInfo(), LD->getRanges());
Hi = DAG.getLoadVP(LD->getAddressingMode(), ExtType, HiVT, dl, Ch, Ptr,
Offset, MaskHi, EVLHi, HiMemVT, MMO,
LD->isExpandingLoad());
}
Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1),
Hi.getValue(1));
ReplaceValueWith(SDValue(LD, 1), Ch);
}
void DAGTypeLegalizer::SplitVecRes_MLOAD(MaskedLoadSDNode *MLD,
SDValue &Lo, SDValue &Hi) {
assert(MLD->isUnindexed() && "Indexed masked load during type legalization!");
EVT LoVT, HiVT;
SDLoc dl(MLD);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(MLD->getValueType(0));
SDValue Ch = MLD->getChain();
SDValue Ptr = MLD->getBasePtr();
SDValue Offset = MLD->getOffset();
assert(Offset.isUndef() && "Unexpected indexed masked load offset");
SDValue Mask = MLD->getMask();
SDValue PassThru = MLD->getPassThru();
Align Alignment = MLD->getOriginalAlign();
ISD::LoadExtType ExtType = MLD->getExtensionType();
SDValue MaskLo, MaskHi;
if (Mask.getOpcode() == ISD::SETCC) {
SplitVecRes_SETCC(Mask.getNode(), MaskLo, MaskHi);
} else {
if (getTypeAction(Mask.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Mask, MaskLo, MaskHi);
else
std::tie(MaskLo, MaskHi) = DAG.SplitVector(Mask, dl);
}
EVT MemoryVT = MLD->getMemoryVT();
EVT LoMemVT, HiMemVT;
bool HiIsEmpty = false;
std::tie(LoMemVT, HiMemVT) =
DAG.GetDependentSplitDestVTs(MemoryVT, LoVT, &HiIsEmpty);
SDValue PassThruLo, PassThruHi;
if (getTypeAction(PassThru.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(PassThru, PassThruLo, PassThruHi);
else
std::tie(PassThruLo, PassThruHi) = DAG.SplitVector(PassThru, dl);
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
MLD->getPointerInfo(), MachineMemOperand::MOLoad,
MemoryLocation::UnknownSize, Alignment, MLD->getAAInfo(),
MLD->getRanges());
Lo = DAG.getMaskedLoad(LoVT, dl, Ch, Ptr, Offset, MaskLo, PassThruLo, LoMemVT,
MMO, MLD->getAddressingMode(), ExtType,
MLD->isExpandingLoad());
if (HiIsEmpty) {
Hi = Lo;
} else {
Ptr = TLI.IncrementMemoryAddress(Ptr, MaskLo, dl, LoMemVT, DAG,
MLD->isExpandingLoad());
MachinePointerInfo MPI;
if (LoMemVT.isScalableVector())
MPI = MachinePointerInfo(MLD->getPointerInfo().getAddrSpace());
else
MPI = MLD->getPointerInfo().getWithOffset(
LoMemVT.getStoreSize().getFixedSize());
MMO = DAG.getMachineFunction().getMachineMemOperand(
MPI, MachineMemOperand::MOLoad, MemoryLocation::UnknownSize, Alignment,
MLD->getAAInfo(), MLD->getRanges());
Hi = DAG.getMaskedLoad(HiVT, dl, Ch, Ptr, Offset, MaskHi, PassThruHi,
HiMemVT, MMO, MLD->getAddressingMode(), ExtType,
MLD->isExpandingLoad());
}
Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1),
Hi.getValue(1));
ReplaceValueWith(SDValue(MLD, 1), Ch);
}
void DAGTypeLegalizer::SplitVecRes_Gather(MemSDNode *N, SDValue &Lo,
SDValue &Hi, bool SplitSETCC) {
EVT LoVT, HiVT;
SDLoc dl(N);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
SDValue Ch = N->getChain();
SDValue Ptr = N->getBasePtr();
struct Operands {
SDValue Mask;
SDValue Index;
SDValue Scale;
} Ops = [&]() -> Operands {
if (auto *MSC = dyn_cast<MaskedGatherSDNode>(N)) {
return {MSC->getMask(), MSC->getIndex(), MSC->getScale()};
}
auto *VPSC = cast<VPGatherSDNode>(N);
return {VPSC->getMask(), VPSC->getIndex(), VPSC->getScale()};
}();
EVT MemoryVT = N->getMemoryVT();
Align Alignment = N->getOriginalAlign();
SDValue MaskLo, MaskHi;
if (SplitSETCC && Ops.Mask.getOpcode() == ISD::SETCC) {
SplitVecRes_SETCC(Ops.Mask.getNode(), MaskLo, MaskHi);
} else {
std::tie(MaskLo, MaskHi) = SplitMask(Ops.Mask, dl);
}
EVT LoMemVT, HiMemVT;
std::tie(LoMemVT, HiMemVT) = DAG.GetSplitDestVTs(MemoryVT);
SDValue IndexHi, IndexLo;
if (getTypeAction(Ops.Index.getValueType()) ==
TargetLowering::TypeSplitVector)
GetSplitVector(Ops.Index, IndexLo, IndexHi);
else
std::tie(IndexLo, IndexHi) = DAG.SplitVector(Ops.Index, dl);
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
N->getPointerInfo(), MachineMemOperand::MOLoad,
MemoryLocation::UnknownSize, Alignment, N->getAAInfo(), N->getRanges());
if (auto *MGT = dyn_cast<MaskedGatherSDNode>(N)) {
SDValue PassThru = MGT->getPassThru();
SDValue PassThruLo, PassThruHi;
if (getTypeAction(PassThru.getValueType()) ==
TargetLowering::TypeSplitVector)
GetSplitVector(PassThru, PassThruLo, PassThruHi);
else
std::tie(PassThruLo, PassThruHi) = DAG.SplitVector(PassThru, dl);
ISD::LoadExtType ExtType = MGT->getExtensionType();
ISD::MemIndexType IndexTy = MGT->getIndexType();
SDValue OpsLo[] = {Ch, PassThruLo, MaskLo, Ptr, IndexLo, Ops.Scale};
Lo = DAG.getMaskedGather(DAG.getVTList(LoVT, MVT::Other), LoMemVT, dl,
OpsLo, MMO, IndexTy, ExtType);
SDValue OpsHi[] = {Ch, PassThruHi, MaskHi, Ptr, IndexHi, Ops.Scale};
Hi = DAG.getMaskedGather(DAG.getVTList(HiVT, MVT::Other), HiMemVT, dl,
OpsHi, MMO, IndexTy, ExtType);
} else {
auto *VPGT = cast<VPGatherSDNode>(N);
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(VPGT->getVectorLength(), MemoryVT, dl);
SDValue OpsLo[] = {Ch, Ptr, IndexLo, Ops.Scale, MaskLo, EVLLo};
Lo = DAG.getGatherVP(DAG.getVTList(LoVT, MVT::Other), LoMemVT, dl, OpsLo,
MMO, VPGT->getIndexType());
SDValue OpsHi[] = {Ch, Ptr, IndexHi, Ops.Scale, MaskHi, EVLHi};
Hi = DAG.getGatherVP(DAG.getVTList(HiVT, MVT::Other), HiMemVT, dl, OpsHi,
MMO, VPGT->getIndexType());
}
Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1),
Hi.getValue(1));
ReplaceValueWith(SDValue(N, 1), Ch);
}
void DAGTypeLegalizer::SplitVecRes_SETCC(SDNode *N, SDValue &Lo, SDValue &Hi) {
assert(N->getValueType(0).isVector() &&
N->getOperand(0).getValueType().isVector() &&
"Operand types must be vectors");
EVT LoVT, HiVT;
SDLoc DL(N);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
SDValue LL, LH, RL, RH;
if (getTypeAction(N->getOperand(0).getValueType()) ==
TargetLowering::TypeSplitVector)
GetSplitVector(N->getOperand(0), LL, LH);
else
std::tie(LL, LH) = DAG.SplitVectorOperand(N, 0);
if (getTypeAction(N->getOperand(1).getValueType()) ==
TargetLowering::TypeSplitVector)
GetSplitVector(N->getOperand(1), RL, RH);
else
std::tie(RL, RH) = DAG.SplitVectorOperand(N, 1);
if (N->getOpcode() == ISD::SETCC) {
Lo = DAG.getNode(N->getOpcode(), DL, LoVT, LL, RL, N->getOperand(2));
Hi = DAG.getNode(N->getOpcode(), DL, HiVT, LH, RH, N->getOperand(2));
} else {
assert(N->getOpcode() == ISD::VP_SETCC && "Expected VP_SETCC opcode");
SDValue MaskLo, MaskHi, EVLLo, EVLHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(3));
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(4), N->getValueType(0), DL);
Lo = DAG.getNode(N->getOpcode(), DL, LoVT, LL, RL, N->getOperand(2), MaskLo,
EVLLo);
Hi = DAG.getNode(N->getOpcode(), DL, HiVT, LH, RH, N->getOperand(2), MaskHi,
EVLHi);
}
}
void DAGTypeLegalizer::SplitVecRes_UnaryOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT LoVT, HiVT;
SDLoc dl(N);
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(N->getValueType(0));
EVT InVT = N->getOperand(0).getValueType();
if (getTypeAction(InVT) == TargetLowering::TypeSplitVector)
GetSplitVector(N->getOperand(0), Lo, Hi);
else
std::tie(Lo, Hi) = DAG.SplitVectorOperand(N, 0);
const SDNodeFlags Flags = N->getFlags();
unsigned Opcode = N->getOpcode();
if (N->getNumOperands() <= 2) {
if (Opcode == ISD::FP_ROUND) {
Lo = DAG.getNode(Opcode, dl, LoVT, Lo, N->getOperand(1), Flags);
Hi = DAG.getNode(Opcode, dl, HiVT, Hi, N->getOperand(1), Flags);
} else {
Lo = DAG.getNode(Opcode, dl, LoVT, Lo, Flags);
Hi = DAG.getNode(Opcode, dl, HiVT, Hi, Flags);
}
return;
}
assert(N->getNumOperands() == 3 && "Unexpected number of operands!");
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue MaskLo, MaskHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(1));
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(2), N->getValueType(0), dl);
Lo = DAG.getNode(Opcode, dl, LoVT, {Lo, MaskLo, EVLLo}, Flags);
Hi = DAG.getNode(Opcode, dl, HiVT, {Hi, MaskHi, EVLHi}, Flags);
}
void DAGTypeLegalizer::SplitVecRes_ExtendOp(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDLoc dl(N);
EVT SrcVT = N->getOperand(0).getValueType();
EVT DestVT = N->getValueType(0);
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(DestVT);
if (SrcVT.getVectorElementCount().isKnownEven() &&
SrcVT.getScalarSizeInBits() * 2 < DestVT.getScalarSizeInBits()) {
LLVMContext &Ctx = *DAG.getContext();
EVT NewSrcVT = SrcVT.widenIntegerVectorElementType(Ctx);
EVT SplitSrcVT = SrcVT.getHalfNumVectorElementsVT(Ctx);
EVT SplitLoVT, SplitHiVT;
std::tie(SplitLoVT, SplitHiVT) = DAG.GetSplitDestVTs(NewSrcVT);
if (TLI.isTypeLegal(SrcVT) && !TLI.isTypeLegal(SplitSrcVT) &&
TLI.isTypeLegal(NewSrcVT) && TLI.isTypeLegal(SplitLoVT)) {
LLVM_DEBUG(dbgs() << "Split vector extend via incremental extend:";
N->dump(&DAG); dbgs() << "\n");
if (!N->isVPOpcode()) {
SDValue NewSrc =
DAG.getNode(N->getOpcode(), dl, NewSrcVT, N->getOperand(0));
std::tie(Lo, Hi) = DAG.SplitVector(NewSrc, dl);
Lo = DAG.getNode(N->getOpcode(), dl, LoVT, Lo);
Hi = DAG.getNode(N->getOpcode(), dl, HiVT, Hi);
return;
}
SDValue NewSrc =
DAG.getNode(N->getOpcode(), dl, NewSrcVT, N->getOperand(0),
N->getOperand(1), N->getOperand(2));
std::tie(Lo, Hi) = DAG.SplitVector(NewSrc, dl);
SDValue MaskLo, MaskHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(1));
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(2), N->getValueType(0), dl);
Lo = DAG.getNode(N->getOpcode(), dl, LoVT, {Lo, MaskLo, EVLLo});
Hi = DAG.getNode(N->getOpcode(), dl, HiVT, {Hi, MaskHi, EVLHi});
return;
}
}
SplitVecRes_UnaryOp(N, Lo, Hi);
}
void DAGTypeLegalizer::SplitVecRes_VECTOR_SHUFFLE(ShuffleVectorSDNode *N,
SDValue &Lo, SDValue &Hi) {
SDValue Inputs[4];
SDLoc DL(N);
GetSplitVector(N->getOperand(0), Inputs[0], Inputs[1]);
GetSplitVector(N->getOperand(1), Inputs[2], Inputs[3]);
EVT NewVT = Inputs[0].getValueType();
unsigned NewElts = NewVT.getVectorNumElements();
auto &&IsConstant = [](const SDValue &N) {
APInt SplatValue;
return N.getResNo() == 0 &&
(ISD::isConstantSplatVector(N.getNode(), SplatValue) ||
ISD::isBuildVectorOfConstantSDNodes(N.getNode()));
};
auto &&BuildVector = [NewElts, &DAG = DAG, NewVT, &DL](SDValue &Input1,
SDValue &Input2,
ArrayRef<int> Mask) {
assert(Input1->getOpcode() == ISD::BUILD_VECTOR &&
Input2->getOpcode() == ISD::BUILD_VECTOR &&
"Expected build vector node.");
EVT EltVT = NewVT.getVectorElementType();
SmallVector<SDValue> Ops(NewElts, DAG.getUNDEF(EltVT));
for (unsigned I = 0; I < NewElts; ++I) {
if (Mask[I] == UndefMaskElem)
continue;
unsigned Idx = Mask[I];
if (Idx >= NewElts)
Ops[I] = Input2.getOperand(Idx - NewElts);
else
Ops[I] = Input1.getOperand(Idx);
if (Ops[I].getValueType().bitsGT(EltVT))
Ops[I] = DAG.getNode(ISD::TRUNCATE, DL, EltVT, Ops[I]);
}
return DAG.getBuildVector(NewVT, DL, Ops);
};
SmallVector<int> OrigMask(N->getMask().begin(), N->getMask().end());
auto &&TryPeekThroughShufflesInputs = [&Inputs, &NewVT, this, NewElts,
&DL](SmallVectorImpl<int> &Mask) {
MapVector<std::pair<SDValue, SDValue>, SmallVector<unsigned>> ShufflesIdxs;
for (unsigned Idx = 0; Idx < array_lengthof(Inputs); ++Idx) {
SDValue Input = Inputs[Idx];
auto *Shuffle = dyn_cast<ShuffleVectorSDNode>(Input.getNode());
if (!Shuffle ||
Input.getOperand(0).getValueType() != Input.getValueType())
continue;
ShufflesIdxs[std::make_pair(Input.getOperand(0), Input.getOperand(1))]
.push_back(Idx);
ShufflesIdxs[std::make_pair(Input.getOperand(1), Input.getOperand(0))]
.push_back(Idx);
}
for (auto &P : ShufflesIdxs) {
if (P.second.size() < 2)
continue;
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
if (Inputs[SrcRegIdx].isUndef()) {
Idx = UndefMaskElem;
continue;
}
auto *Shuffle =
dyn_cast<ShuffleVectorSDNode>(Inputs[SrcRegIdx].getNode());
if (!Shuffle || !is_contained(P.second, SrcRegIdx))
continue;
int MaskElt = Shuffle->getMaskElt(Idx % NewElts);
if (MaskElt == UndefMaskElem) {
Idx = UndefMaskElem;
continue;
}
Idx = MaskElt % NewElts +
P.second[Shuffle->getOperand(MaskElt / NewElts) == P.first.first
? 0
: 1] *
NewElts;
}
Inputs[P.second[0]] = P.first.first;
Inputs[P.second[1]] = P.first.second;
P.second.clear();
ShufflesIdxs[std::make_pair(P.first.second, P.first.first)].clear();
}
SmallBitVector UsedSubVector(2 * array_lengthof(Inputs));
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
if (Inputs[SrcRegIdx].isUndef()) {
Idx = UndefMaskElem;
continue;
}
TargetLowering::LegalizeTypeAction TypeAction =
getTypeAction(Inputs[SrcRegIdx].getValueType());
if (Inputs[SrcRegIdx].getOpcode() == ISD::CONCAT_VECTORS &&
Inputs[SrcRegIdx].getNumOperands() == 2 &&
!Inputs[SrcRegIdx].getOperand(1).isUndef() &&
(TypeAction == TargetLowering::TypeLegal ||
TypeAction == TargetLowering::TypeWidenVector))
UsedSubVector.set(2 * SrcRegIdx + (Idx % NewElts) / (NewElts / 2));
}
if (UsedSubVector.count() > 1) {
SmallVector<SmallVector<std::pair<unsigned, int>, 2>> Pairs;
for (unsigned I = 0; I < array_lengthof(Inputs); ++I) {
if (UsedSubVector.test(2 * I) == UsedSubVector.test(2 * I + 1))
continue;
if (Pairs.empty() || Pairs.back().size() == 2)
Pairs.emplace_back();
if (UsedSubVector.test(2 * I)) {
Pairs.back().emplace_back(I, 0);
} else {
assert(UsedSubVector.test(2 * I + 1) &&
"Expected to be used one of the subvectors.");
Pairs.back().emplace_back(I, 1);
}
}
if (!Pairs.empty() && Pairs.front().size() > 1) {
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
auto *It = find_if(
Pairs, [SrcRegIdx](ArrayRef<std::pair<unsigned, int>> Idxs) {
return Idxs.front().first == SrcRegIdx ||
Idxs.back().first == SrcRegIdx;
});
if (It == Pairs.end())
continue;
Idx = It->front().first * NewElts + (Idx % NewElts) % (NewElts / 2) +
(SrcRegIdx == It->front().first ? 0 : (NewElts / 2));
}
for (ArrayRef<std::pair<unsigned, int>> Idxs : Pairs) {
Inputs[Idxs.front().first] = DAG.getNode(
ISD::CONCAT_VECTORS, DL,
Inputs[Idxs.front().first].getValueType(),
Inputs[Idxs.front().first].getOperand(Idxs.front().second),
Inputs[Idxs.back().first].getOperand(Idxs.back().second));
}
}
}
bool Changed;
do {
Changed = false;
for (unsigned I = 0; I < array_lengthof(Inputs); ++I) {
auto *Shuffle = dyn_cast<ShuffleVectorSDNode>(Inputs[I].getNode());
if (!Shuffle)
continue;
if (Shuffle->getOperand(0).getValueType() != NewVT)
continue;
int Op = -1;
if (!Inputs[I].hasOneUse() && Shuffle->getOperand(1).isUndef() &&
!Shuffle->isSplat()) {
Op = 0;
} else if (!Inputs[I].hasOneUse() &&
!Shuffle->getOperand(1).isUndef()) {
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
if (SrcRegIdx != I)
continue;
int MaskElt = Shuffle->getMaskElt(Idx % NewElts);
if (MaskElt == UndefMaskElem) {
Idx = UndefMaskElem;
continue;
}
int OpIdx = MaskElt / NewElts;
if (Op == -1) {
Op = OpIdx;
continue;
}
if (Op != OpIdx) {
Op = -1;
break;
}
}
}
if (Op < 0) {
for (int OpIdx = 0; OpIdx < 2; ++OpIdx) {
if (Shuffle->getOperand(OpIdx).isUndef())
continue;
auto *It = find(Inputs, Shuffle->getOperand(OpIdx));
if (It == std::end(Inputs))
continue;
int FoundOp = std::distance(std::begin(Inputs), It);
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
if (SrcRegIdx != I)
continue;
int MaskElt = Shuffle->getMaskElt(Idx % NewElts);
if (MaskElt == UndefMaskElem) {
Idx = UndefMaskElem;
continue;
}
int MaskIdx = MaskElt / NewElts;
if (OpIdx == MaskIdx)
Idx = MaskElt % NewElts + FoundOp * NewElts;
}
Op = (OpIdx + 1) % 2;
break;
}
}
if (Op >= 0) {
Changed = true;
Inputs[I] = Shuffle->getOperand(Op);
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
if (SrcRegIdx != I)
continue;
int MaskElt = Shuffle->getMaskElt(Idx % NewElts);
int OpIdx = MaskElt / NewElts;
if (OpIdx != Op)
continue;
Idx = MaskElt % NewElts + SrcRegIdx * NewElts;
}
}
}
} while (Changed);
};
TryPeekThroughShufflesInputs(OrigMask);
auto &&MakeUniqueInputs = [&Inputs, &IsConstant,
NewElts](SmallVectorImpl<int> &Mask) {
SetVector<SDValue> UniqueInputs;
SetVector<SDValue> UniqueConstantInputs;
for (unsigned I = 0; I < array_lengthof(Inputs); ++I) {
if (IsConstant(Inputs[I]))
UniqueConstantInputs.insert(Inputs[I]);
else if (!Inputs[I].isUndef())
UniqueInputs.insert(Inputs[I]);
}
if (UniqueInputs.size() != array_lengthof(Inputs)) {
auto &&UniqueVec = UniqueInputs.takeVector();
auto &&UniqueConstantVec = UniqueConstantInputs.takeVector();
unsigned ConstNum = UniqueConstantVec.size();
for (int &Idx : Mask) {
if (Idx == UndefMaskElem)
continue;
unsigned SrcRegIdx = Idx / NewElts;
if (Inputs[SrcRegIdx].isUndef()) {
Idx = UndefMaskElem;
continue;
}
const auto It = find(UniqueConstantVec, Inputs[SrcRegIdx]);
if (It != UniqueConstantVec.end()) {
Idx = (Idx % NewElts) +
NewElts * std::distance(UniqueConstantVec.begin(), It);
assert(Idx >= 0 && "Expected defined mask idx.");
continue;
}
const auto RegIt = find(UniqueVec, Inputs[SrcRegIdx]);
assert(RegIt != UniqueVec.end() && "Cannot find non-const value.");
Idx = (Idx % NewElts) +
NewElts * (std::distance(UniqueVec.begin(), RegIt) + ConstNum);
assert(Idx >= 0 && "Expected defined mask idx.");
}
copy(UniqueConstantVec, std::begin(Inputs));
copy(UniqueVec, std::next(std::begin(Inputs), ConstNum));
}
};
MakeUniqueInputs(OrigMask);
SDValue OrigInputs[4];
copy(Inputs, std::begin(OrigInputs));
for (unsigned High = 0; High < 2; ++High) {
SDValue &Output = High ? Hi : Lo;
unsigned FirstMaskIdx = High * NewElts;
SmallVector<int> Mask(NewElts * array_lengthof(Inputs), UndefMaskElem);
copy(makeArrayRef(OrigMask).slice(FirstMaskIdx, NewElts), Mask.begin());
assert(!Output && "Expected default initialized initial value.");
TryPeekThroughShufflesInputs(Mask);
MakeUniqueInputs(Mask);
SDValue TmpInputs[4];
copy(Inputs, std::begin(TmpInputs));
int UsedIdx = -1;
bool SecondIteration = false;
auto &&AccumulateResults = [&UsedIdx, &SecondIteration](unsigned Idx) {
if (UsedIdx < 0) {
UsedIdx = Idx;
return false;
}
if (UsedIdx >= 0 && static_cast<unsigned>(UsedIdx) == Idx)
SecondIteration = true;
return SecondIteration;
};
processShuffleMasks(
Mask, array_lengthof(Inputs), array_lengthof(Inputs),
1,
[&Output, &DAG = DAG, NewVT]() { Output = DAG.getUNDEF(NewVT); },
[&Output, &DAG = DAG, NewVT, &DL, &Inputs,
&BuildVector](ArrayRef<int> Mask, unsigned Idx, unsigned ) {
if (Inputs[Idx]->getOpcode() == ISD::BUILD_VECTOR)
Output = BuildVector(Inputs[Idx], Inputs[Idx], Mask);
else
Output = DAG.getVectorShuffle(NewVT, DL, Inputs[Idx],
DAG.getUNDEF(NewVT), Mask);
Inputs[Idx] = Output;
},
[&AccumulateResults, &Output, &DAG = DAG, NewVT, &DL, &Inputs,
&TmpInputs,
&BuildVector](ArrayRef<int> Mask, unsigned Idx1, unsigned Idx2) {
if (AccumulateResults(Idx1)) {
if (Inputs[Idx1]->getOpcode() == ISD::BUILD_VECTOR &&
Inputs[Idx2]->getOpcode() == ISD::BUILD_VECTOR)
Output = BuildVector(Inputs[Idx1], Inputs[Idx2], Mask);
else
Output = DAG.getVectorShuffle(NewVT, DL, Inputs[Idx1],
Inputs[Idx2], Mask);
} else {
if (TmpInputs[Idx1]->getOpcode() == ISD::BUILD_VECTOR &&
TmpInputs[Idx2]->getOpcode() == ISD::BUILD_VECTOR)
Output = BuildVector(TmpInputs[Idx1], TmpInputs[Idx2], Mask);
else
Output = DAG.getVectorShuffle(NewVT, DL, TmpInputs[Idx1],
TmpInputs[Idx2], Mask);
}
Inputs[Idx1] = Output;
});
copy(OrigInputs, std::begin(Inputs));
}
}
void DAGTypeLegalizer::SplitVecRes_VAARG(SDNode *N, SDValue &Lo, SDValue &Hi) {
EVT OVT = N->getValueType(0);
EVT NVT = OVT.getHalfNumVectorElementsVT(*DAG.getContext());
SDValue Chain = N->getOperand(0);
SDValue Ptr = N->getOperand(1);
SDValue SV = N->getOperand(2);
SDLoc dl(N);
const Align Alignment =
DAG.getDataLayout().getABITypeAlign(NVT.getTypeForEVT(*DAG.getContext()));
Lo = DAG.getVAArg(NVT, dl, Chain, Ptr, SV, Alignment.value());
Hi = DAG.getVAArg(NVT, dl, Lo.getValue(1), Ptr, SV, Alignment.value());
Chain = Hi.getValue(1);
ReplaceValueWith(SDValue(N, 1), Chain);
}
void DAGTypeLegalizer::SplitVecRes_FP_TO_XINT_SAT(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT DstVTLo, DstVTHi;
std::tie(DstVTLo, DstVTHi) = DAG.GetSplitDestVTs(N->getValueType(0));
SDLoc dl(N);
SDValue SrcLo, SrcHi;
EVT SrcVT = N->getOperand(0).getValueType();
if (getTypeAction(SrcVT) == TargetLowering::TypeSplitVector)
GetSplitVector(N->getOperand(0), SrcLo, SrcHi);
else
std::tie(SrcLo, SrcHi) = DAG.SplitVectorOperand(N, 0);
Lo = DAG.getNode(N->getOpcode(), dl, DstVTLo, SrcLo, N->getOperand(1));
Hi = DAG.getNode(N->getOpcode(), dl, DstVTHi, SrcHi, N->getOperand(1));
}
void DAGTypeLegalizer::SplitVecRes_VECTOR_REVERSE(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDValue InLo, InHi;
GetSplitVector(N->getOperand(0), InLo, InHi);
SDLoc DL(N);
Lo = DAG.getNode(ISD::VECTOR_REVERSE, DL, InHi.getValueType(), InHi);
Hi = DAG.getNode(ISD::VECTOR_REVERSE, DL, InLo.getValueType(), InLo);
}
void DAGTypeLegalizer::SplitVecRes_VECTOR_SPLICE(SDNode *N, SDValue &Lo,
SDValue &Hi) {
EVT VT = N->getValueType(0);
SDLoc DL(N);
EVT LoVT, HiVT;
std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(VT);
SDValue Expanded = TLI.expandVectorSplice(N, DAG);
Lo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, LoVT, Expanded,
DAG.getVectorIdxConstant(0, DL));
Hi =
DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, HiVT, Expanded,
DAG.getVectorIdxConstant(LoVT.getVectorMinNumElements(), DL));
}
bool DAGTypeLegalizer::SplitVectorOperand(SDNode *N, unsigned OpNo) {
LLVM_DEBUG(dbgs() << "Split node operand: "; N->dump(&DAG); dbgs() << "\n");
SDValue Res = SDValue();
if (CustomLowerNode(N, N->getOperand(OpNo).getValueType(), false))
return false;
switch (N->getOpcode()) {
default:
#ifndef NDEBUG
dbgs() << "SplitVectorOperand Op #" << OpNo << ": ";
N->dump(&DAG);
dbgs() << "\n";
#endif
report_fatal_error("Do not know how to split this operator's "
"operand!\n");
case ISD::VP_SETCC:
case ISD::SETCC: Res = SplitVecOp_VSETCC(N); break;
case ISD::BITCAST: Res = SplitVecOp_BITCAST(N); break;
case ISD::EXTRACT_SUBVECTOR: Res = SplitVecOp_EXTRACT_SUBVECTOR(N); break;
case ISD::INSERT_SUBVECTOR: Res = SplitVecOp_INSERT_SUBVECTOR(N, OpNo); break;
case ISD::EXTRACT_VECTOR_ELT:Res = SplitVecOp_EXTRACT_VECTOR_ELT(N); break;
case ISD::CONCAT_VECTORS: Res = SplitVecOp_CONCAT_VECTORS(N); break;
case ISD::VP_TRUNCATE:
case ISD::TRUNCATE:
Res = SplitVecOp_TruncateHelper(N);
break;
case ISD::STRICT_FP_ROUND:
case ISD::VP_FP_ROUND:
case ISD::FP_ROUND: Res = SplitVecOp_FP_ROUND(N); break;
case ISD::FCOPYSIGN: Res = SplitVecOp_FCOPYSIGN(N); break;
case ISD::STORE:
Res = SplitVecOp_STORE(cast<StoreSDNode>(N), OpNo);
break;
case ISD::VP_STORE:
Res = SplitVecOp_VP_STORE(cast<VPStoreSDNode>(N), OpNo);
break;
case ISD::MSTORE:
Res = SplitVecOp_MSTORE(cast<MaskedStoreSDNode>(N), OpNo);
break;
case ISD::MSCATTER:
case ISD::VP_SCATTER:
Res = SplitVecOp_Scatter(cast<MemSDNode>(N), OpNo);
break;
case ISD::MGATHER:
case ISD::VP_GATHER:
Res = SplitVecOp_Gather(cast<MemSDNode>(N), OpNo);
break;
case ISD::VSELECT:
Res = SplitVecOp_VSELECT(N, OpNo);
break;
case ISD::STRICT_SINT_TO_FP:
case ISD::STRICT_UINT_TO_FP:
case ISD::SINT_TO_FP:
case ISD::UINT_TO_FP:
if (N->getValueType(0).bitsLT(
N->getOperand(N->isStrictFPOpcode() ? 1 : 0).getValueType()))
Res = SplitVecOp_TruncateHelper(N);
else
Res = SplitVecOp_UnaryOp(N);
break;
case ISD::FP_TO_SINT_SAT:
case ISD::FP_TO_UINT_SAT:
Res = SplitVecOp_FP_TO_XINT_SAT(N);
break;
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT:
case ISD::STRICT_FP_TO_SINT:
case ISD::STRICT_FP_TO_UINT:
case ISD::STRICT_FP_EXTEND:
case ISD::FP_EXTEND:
case ISD::SIGN_EXTEND:
case ISD::ZERO_EXTEND:
case ISD::ANY_EXTEND:
case ISD::FTRUNC:
Res = SplitVecOp_UnaryOp(N);
break;
case ISD::ANY_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
Res = SplitVecOp_ExtVecInRegOp(N);
break;
case ISD::VECREDUCE_FADD:
case ISD::VECREDUCE_FMUL:
case ISD::VECREDUCE_ADD:
case ISD::VECREDUCE_MUL:
case ISD::VECREDUCE_AND:
case ISD::VECREDUCE_OR:
case ISD::VECREDUCE_XOR:
case ISD::VECREDUCE_SMAX:
case ISD::VECREDUCE_SMIN:
case ISD::VECREDUCE_UMAX:
case ISD::VECREDUCE_UMIN:
case ISD::VECREDUCE_FMAX:
case ISD::VECREDUCE_FMIN:
Res = SplitVecOp_VECREDUCE(N, OpNo);
break;
case ISD::VECREDUCE_SEQ_FADD:
case ISD::VECREDUCE_SEQ_FMUL:
Res = SplitVecOp_VECREDUCE_SEQ(N);
break;
case ISD::VP_REDUCE_FADD:
case ISD::VP_REDUCE_SEQ_FADD:
case ISD::VP_REDUCE_FMUL:
case ISD::VP_REDUCE_SEQ_FMUL:
case ISD::VP_REDUCE_ADD:
case ISD::VP_REDUCE_MUL:
case ISD::VP_REDUCE_AND:
case ISD::VP_REDUCE_OR:
case ISD::VP_REDUCE_XOR:
case ISD::VP_REDUCE_SMAX:
case ISD::VP_REDUCE_SMIN:
case ISD::VP_REDUCE_UMAX:
case ISD::VP_REDUCE_UMIN:
case ISD::VP_REDUCE_FMAX:
case ISD::VP_REDUCE_FMIN:
Res = SplitVecOp_VP_REDUCE(N, OpNo);
break;
}
if (!Res.getNode()) return false;
if (Res.getNode() == N)
return true;
if (N->isStrictFPOpcode())
assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == 2 &&
"Invalid operand expansion");
else
assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == 1 &&
"Invalid operand expansion");
ReplaceValueWith(SDValue(N, 0), Res);
return false;
}
SDValue DAGTypeLegalizer::SplitVecOp_VSELECT(SDNode *N, unsigned OpNo) {
assert(OpNo == 0 && "Illegal operand must be mask");
SDValue Mask = N->getOperand(0);
SDValue Src0 = N->getOperand(1);
SDValue Src1 = N->getOperand(2);
EVT Src0VT = Src0.getValueType();
SDLoc DL(N);
assert(Mask.getValueType().isVector() && "VSELECT without a vector mask?");
SDValue Lo, Hi;
GetSplitVector(N->getOperand(0), Lo, Hi);
assert(Lo.getValueType() == Hi.getValueType() &&
"Lo and Hi have differing types");
EVT LoOpVT, HiOpVT;
std::tie(LoOpVT, HiOpVT) = DAG.GetSplitDestVTs(Src0VT);
assert(LoOpVT == HiOpVT && "Asymmetric vector split?");
SDValue LoOp0, HiOp0, LoOp1, HiOp1, LoMask, HiMask;
std::tie(LoOp0, HiOp0) = DAG.SplitVector(Src0, DL);
std::tie(LoOp1, HiOp1) = DAG.SplitVector(Src1, DL);
std::tie(LoMask, HiMask) = DAG.SplitVector(Mask, DL);
SDValue LoSelect =
DAG.getNode(ISD::VSELECT, DL, LoOpVT, LoMask, LoOp0, LoOp1);
SDValue HiSelect =
DAG.getNode(ISD::VSELECT, DL, HiOpVT, HiMask, HiOp0, HiOp1);
return DAG.getNode(ISD::CONCAT_VECTORS, DL, Src0VT, LoSelect, HiSelect);
}
SDValue DAGTypeLegalizer::SplitVecOp_VECREDUCE(SDNode *N, unsigned OpNo) {
EVT ResVT = N->getValueType(0);
SDValue Lo, Hi;
SDLoc dl(N);
SDValue VecOp = N->getOperand(OpNo);
EVT VecVT = VecOp.getValueType();
assert(VecVT.isVector() && "Can only split reduce vector operand");
GetSplitVector(VecOp, Lo, Hi);
EVT LoOpVT, HiOpVT;
std::tie(LoOpVT, HiOpVT) = DAG.GetSplitDestVTs(VecVT);
unsigned CombineOpc = ISD::getVecReduceBaseOpcode(N->getOpcode());
SDValue Partial = DAG.getNode(CombineOpc, dl, LoOpVT, Lo, Hi, N->getFlags());
return DAG.getNode(N->getOpcode(), dl, ResVT, Partial, N->getFlags());
}
SDValue DAGTypeLegalizer::SplitVecOp_VECREDUCE_SEQ(SDNode *N) {
EVT ResVT = N->getValueType(0);
SDValue Lo, Hi;
SDLoc dl(N);
SDValue AccOp = N->getOperand(0);
SDValue VecOp = N->getOperand(1);
SDNodeFlags Flags = N->getFlags();
EVT VecVT = VecOp.getValueType();
assert(VecVT.isVector() && "Can only split reduce vector operand");
GetSplitVector(VecOp, Lo, Hi);
EVT LoOpVT, HiOpVT;
std::tie(LoOpVT, HiOpVT) = DAG.GetSplitDestVTs(VecVT);
SDValue Partial = DAG.getNode(N->getOpcode(), dl, ResVT, AccOp, Lo, Flags);
return DAG.getNode(N->getOpcode(), dl, ResVT, Partial, Hi, Flags);
}
SDValue DAGTypeLegalizer::SplitVecOp_VP_REDUCE(SDNode *N, unsigned OpNo) {
assert(N->isVPOpcode() && "Expected VP opcode");
assert(OpNo == 1 && "Can only split reduce vector operand");
unsigned Opc = N->getOpcode();
EVT ResVT = N->getValueType(0);
SDValue Lo, Hi;
SDLoc dl(N);
SDValue VecOp = N->getOperand(OpNo);
EVT VecVT = VecOp.getValueType();
assert(VecVT.isVector() && "Can only split reduce vector operand");
GetSplitVector(VecOp, Lo, Hi);
SDValue MaskLo, MaskHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(2));
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) = DAG.SplitEVL(N->getOperand(3), VecVT, dl);
const SDNodeFlags Flags = N->getFlags();
SDValue ResLo =
DAG.getNode(Opc, dl, ResVT, {N->getOperand(0), Lo, MaskLo, EVLLo}, Flags);
return DAG.getNode(Opc, dl, ResVT, {ResLo, Hi, MaskHi, EVLHi}, Flags);
}
SDValue DAGTypeLegalizer::SplitVecOp_UnaryOp(SDNode *N) {
EVT ResVT = N->getValueType(0);
SDValue Lo, Hi;
SDLoc dl(N);
GetSplitVector(N->getOperand(N->isStrictFPOpcode() ? 1 : 0), Lo, Hi);
EVT InVT = Lo.getValueType();
EVT OutVT = EVT::getVectorVT(*DAG.getContext(), ResVT.getVectorElementType(),
InVT.getVectorElementCount());
if (N->isStrictFPOpcode()) {
Lo = DAG.getNode(N->getOpcode(), dl, { OutVT, MVT::Other },
{ N->getOperand(0), Lo });
Hi = DAG.getNode(N->getOpcode(), dl, { OutVT, MVT::Other },
{ N->getOperand(0), Hi });
SDValue Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1),
Hi.getValue(1));
ReplaceValueWith(SDValue(N, 1), Ch);
} else if (N->getNumOperands() == 3) {
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue MaskLo, MaskHi, EVLLo, EVLHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(1));
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(2), N->getValueType(0), dl);
Lo = DAG.getNode(N->getOpcode(), dl, OutVT, Lo, MaskLo, EVLLo);
Hi = DAG.getNode(N->getOpcode(), dl, OutVT, Hi, MaskHi, EVLHi);
} else {
Lo = DAG.getNode(N->getOpcode(), dl, OutVT, Lo);
Hi = DAG.getNode(N->getOpcode(), dl, OutVT, Hi);
}
return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResVT, Lo, Hi);
}
SDValue DAGTypeLegalizer::SplitVecOp_BITCAST(SDNode *N) {
SDValue Lo, Hi;
GetSplitVector(N->getOperand(0), Lo, Hi);
Lo = BitConvertToInteger(Lo);
Hi = BitConvertToInteger(Hi);
if (DAG.getDataLayout().isBigEndian())
std::swap(Lo, Hi);
return DAG.getNode(ISD::BITCAST, SDLoc(N), N->getValueType(0),
JoinIntegers(Lo, Hi));
}
SDValue DAGTypeLegalizer::SplitVecOp_INSERT_SUBVECTOR(SDNode *N,
unsigned OpNo) {
assert(OpNo == 1 && "Invalid OpNo; can only split SubVec.");
EVT ResVT = N->getValueType(0);
SDValue Vec = N->getOperand(0);
SDValue SubVec = N->getOperand(1);
SDValue Idx = N->getOperand(2);
SDLoc dl(N);
SDValue Lo, Hi;
GetSplitVector(SubVec, Lo, Hi);
uint64_t IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
uint64_t LoElts = Lo.getValueType().getVectorMinNumElements();
SDValue FirstInsertion =
DAG.getNode(ISD::INSERT_SUBVECTOR, dl, ResVT, Vec, Lo, Idx);
SDValue SecondInsertion =
DAG.getNode(ISD::INSERT_SUBVECTOR, dl, ResVT, FirstInsertion, Hi,
DAG.getVectorIdxConstant(IdxVal + LoElts, dl));
return SecondInsertion;
}
SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_SUBVECTOR(SDNode *N) {
EVT SubVT = N->getValueType(0);
SDValue Idx = N->getOperand(1);
SDLoc dl(N);
SDValue Lo, Hi;
if (SubVT.isScalableVector() !=
N->getOperand(0).getValueType().isScalableVector())
report_fatal_error("Extracting a fixed-length vector from an illegal "
"scalable vector is not yet supported");
GetSplitVector(N->getOperand(0), Lo, Hi);
uint64_t LoElts = Lo.getValueType().getVectorMinNumElements();
uint64_t IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
if (IdxVal < LoElts) {
assert(IdxVal + SubVT.getVectorMinNumElements() <= LoElts &&
"Extracted subvector crosses vector split!");
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, SubVT, Lo, Idx);
} else {
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, SubVT, Hi,
DAG.getVectorIdxConstant(IdxVal - LoElts, dl));
}
}
SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N) {
SDValue Vec = N->getOperand(0);
SDValue Idx = N->getOperand(1);
EVT VecVT = Vec.getValueType();
if (isa<ConstantSDNode>(Idx)) {
uint64_t IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
SDValue Lo, Hi;
GetSplitVector(Vec, Lo, Hi);
uint64_t LoElts = Lo.getValueType().getVectorMinNumElements();
if (IdxVal < LoElts)
return SDValue(DAG.UpdateNodeOperands(N, Lo, Idx), 0);
else if (!Vec.getValueType().isScalableVector())
return SDValue(DAG.UpdateNodeOperands(N, Hi,
DAG.getConstant(IdxVal - LoElts, SDLoc(N),
Idx.getValueType())), 0);
}
if (CustomLowerNode(N, N->getValueType(0), true))
return SDValue();
SDLoc dl(N);
EVT EltVT = VecVT.getVectorElementType();
if (VecVT.getScalarSizeInBits() < 8) {
EltVT = MVT::i8;
VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT,
VecVT.getVectorElementCount());
Vec = DAG.getNode(ISD::ANY_EXTEND, dl, VecVT, Vec);
}
Align SmallestAlign = DAG.getReducedAlign(VecVT, false);
SDValue StackPtr =
DAG.CreateStackTemporary(VecVT.getStoreSize(), SmallestAlign);
auto &MF = DAG.getMachineFunction();
auto FrameIndex = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo,
SmallestAlign);
StackPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx);
if (N->getValueType(0).bitsLT(EltVT)) {
SDValue Load = DAG.getLoad(EltVT, dl, Store, StackPtr,
MachinePointerInfo::getUnknownStack(DAG.getMachineFunction()));
return DAG.getZExtOrTrunc(Load, dl, N->getValueType(0));
}
return DAG.getExtLoad(
ISD::EXTLOAD, dl, N->getValueType(0), Store, StackPtr,
MachinePointerInfo::getUnknownStack(DAG.getMachineFunction()), EltVT,
commonAlignment(SmallestAlign, EltVT.getFixedSizeInBits() / 8));
}
SDValue DAGTypeLegalizer::SplitVecOp_ExtVecInRegOp(SDNode *N) {
SDValue Lo, Hi;
SplitVecRes_ExtVecInRegOp(N, Lo, Hi);
return DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(N), N->getValueType(0), Lo, Hi);
}
SDValue DAGTypeLegalizer::SplitVecOp_Gather(MemSDNode *N, unsigned OpNo) {
(void)OpNo;
SDValue Lo, Hi;
SplitVecRes_Gather(N, Lo, Hi);
SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, N, N->getValueType(0), Lo, Hi);
ReplaceValueWith(SDValue(N, 0), Res);
return SDValue();
}
SDValue DAGTypeLegalizer::SplitVecOp_VP_STORE(VPStoreSDNode *N, unsigned OpNo) {
assert(N->isUnindexed() && "Indexed vp_store of vector?");
SDValue Ch = N->getChain();
SDValue Ptr = N->getBasePtr();
SDValue Offset = N->getOffset();
assert(Offset.isUndef() && "Unexpected VP store offset");
SDValue Mask = N->getMask();
SDValue EVL = N->getVectorLength();
SDValue Data = N->getValue();
Align Alignment = N->getOriginalAlign();
SDLoc DL(N);
SDValue DataLo, DataHi;
if (getTypeAction(Data.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Data, DataLo, DataHi);
else
std::tie(DataLo, DataHi) = DAG.SplitVector(Data, DL);
SDValue MaskLo, MaskHi;
if (OpNo == 1 && Mask.getOpcode() == ISD::SETCC) {
SplitVecRes_SETCC(Mask.getNode(), MaskLo, MaskHi);
} else {
if (getTypeAction(Mask.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Mask, MaskLo, MaskHi);
else
std::tie(MaskLo, MaskHi) = DAG.SplitVector(Mask, DL);
}
EVT MemoryVT = N->getMemoryVT();
EVT LoMemVT, HiMemVT;
bool HiIsEmpty = false;
std::tie(LoMemVT, HiMemVT) =
DAG.GetDependentSplitDestVTs(MemoryVT, DataLo.getValueType(), &HiIsEmpty);
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) = DAG.SplitEVL(EVL, Data.getValueType(), DL);
SDValue Lo, Hi;
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
N->getPointerInfo(), MachineMemOperand::MOStore,
MemoryLocation::UnknownSize, Alignment, N->getAAInfo(), N->getRanges());
Lo = DAG.getStoreVP(Ch, DL, DataLo, Ptr, Offset, MaskLo, EVLLo, LoMemVT, MMO,
N->getAddressingMode(), N->isTruncatingStore(),
N->isCompressingStore());
if (HiIsEmpty)
return Lo;
Ptr = TLI.IncrementMemoryAddress(Ptr, MaskLo, DL, LoMemVT, DAG,
N->isCompressingStore());
MachinePointerInfo MPI;
if (LoMemVT.isScalableVector()) {
Alignment = commonAlignment(Alignment,
LoMemVT.getSizeInBits().getKnownMinSize() / 8);
MPI = MachinePointerInfo(N->getPointerInfo().getAddrSpace());
} else
MPI = N->getPointerInfo().getWithOffset(
LoMemVT.getStoreSize().getFixedSize());
MMO = DAG.getMachineFunction().getMachineMemOperand(
MPI, MachineMemOperand::MOStore, MemoryLocation::UnknownSize, Alignment,
N->getAAInfo(), N->getRanges());
Hi = DAG.getStoreVP(Ch, DL, DataHi, Ptr, Offset, MaskHi, EVLHi, HiMemVT, MMO,
N->getAddressingMode(), N->isTruncatingStore(),
N->isCompressingStore());
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi);
}
SDValue DAGTypeLegalizer::SplitVecOp_MSTORE(MaskedStoreSDNode *N,
unsigned OpNo) {
assert(N->isUnindexed() && "Indexed masked store of vector?");
SDValue Ch = N->getChain();
SDValue Ptr = N->getBasePtr();
SDValue Offset = N->getOffset();
assert(Offset.isUndef() && "Unexpected indexed masked store offset");
SDValue Mask = N->getMask();
SDValue Data = N->getValue();
Align Alignment = N->getOriginalAlign();
SDLoc DL(N);
SDValue DataLo, DataHi;
if (getTypeAction(Data.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Data, DataLo, DataHi);
else
std::tie(DataLo, DataHi) = DAG.SplitVector(Data, DL);
SDValue MaskLo, MaskHi;
if (OpNo == 1 && Mask.getOpcode() == ISD::SETCC) {
SplitVecRes_SETCC(Mask.getNode(), MaskLo, MaskHi);
} else {
if (getTypeAction(Mask.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Mask, MaskLo, MaskHi);
else
std::tie(MaskLo, MaskHi) = DAG.SplitVector(Mask, DL);
}
EVT MemoryVT = N->getMemoryVT();
EVT LoMemVT, HiMemVT;
bool HiIsEmpty = false;
std::tie(LoMemVT, HiMemVT) =
DAG.GetDependentSplitDestVTs(MemoryVT, DataLo.getValueType(), &HiIsEmpty);
SDValue Lo, Hi, Res;
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
N->getPointerInfo(), MachineMemOperand::MOStore,
MemoryLocation::UnknownSize, Alignment, N->getAAInfo(), N->getRanges());
Lo = DAG.getMaskedStore(Ch, DL, DataLo, Ptr, Offset, MaskLo, LoMemVT, MMO,
N->getAddressingMode(), N->isTruncatingStore(),
N->isCompressingStore());
if (HiIsEmpty) {
Res = Lo;
} else {
Ptr = TLI.IncrementMemoryAddress(Ptr, MaskLo, DL, LoMemVT, DAG,
N->isCompressingStore());
MachinePointerInfo MPI;
if (LoMemVT.isScalableVector()) {
Alignment = commonAlignment(
Alignment, LoMemVT.getSizeInBits().getKnownMinSize() / 8);
MPI = MachinePointerInfo(N->getPointerInfo().getAddrSpace());
} else
MPI = N->getPointerInfo().getWithOffset(
LoMemVT.getStoreSize().getFixedSize());
MMO = DAG.getMachineFunction().getMachineMemOperand(
MPI, MachineMemOperand::MOStore, MemoryLocation::UnknownSize, Alignment,
N->getAAInfo(), N->getRanges());
Hi = DAG.getMaskedStore(Ch, DL, DataHi, Ptr, Offset, MaskHi, HiMemVT, MMO,
N->getAddressingMode(), N->isTruncatingStore(),
N->isCompressingStore());
Res = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi);
}
return Res;
}
SDValue DAGTypeLegalizer::SplitVecOp_Scatter(MemSDNode *N, unsigned OpNo) {
SDValue Ch = N->getChain();
SDValue Ptr = N->getBasePtr();
EVT MemoryVT = N->getMemoryVT();
Align Alignment = N->getOriginalAlign();
SDLoc DL(N);
struct Operands {
SDValue Mask;
SDValue Index;
SDValue Scale;
SDValue Data;
} Ops = [&]() -> Operands {
if (auto *MSC = dyn_cast<MaskedScatterSDNode>(N)) {
return {MSC->getMask(), MSC->getIndex(), MSC->getScale(),
MSC->getValue()};
}
auto *VPSC = cast<VPScatterSDNode>(N);
return {VPSC->getMask(), VPSC->getIndex(), VPSC->getScale(),
VPSC->getValue()};
}();
EVT LoMemVT, HiMemVT;
std::tie(LoMemVT, HiMemVT) = DAG.GetSplitDestVTs(MemoryVT);
SDValue DataLo, DataHi;
if (getTypeAction(Ops.Data.getValueType()) == TargetLowering::TypeSplitVector)
GetSplitVector(Ops.Data, DataLo, DataHi);
else
std::tie(DataLo, DataHi) = DAG.SplitVector(Ops.Data, DL);
SDValue MaskLo, MaskHi;
if (OpNo == 1 && Ops.Mask.getOpcode() == ISD::SETCC) {
SplitVecRes_SETCC(Ops.Mask.getNode(), MaskLo, MaskHi);
} else {
std::tie(MaskLo, MaskHi) = SplitMask(Ops.Mask, DL);
}
SDValue IndexHi, IndexLo;
if (getTypeAction(Ops.Index.getValueType()) ==
TargetLowering::TypeSplitVector)
GetSplitVector(Ops.Index, IndexLo, IndexHi);
else
std::tie(IndexLo, IndexHi) = DAG.SplitVector(Ops.Index, DL);
SDValue Lo;
MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
N->getPointerInfo(), MachineMemOperand::MOStore,
MemoryLocation::UnknownSize, Alignment, N->getAAInfo(), N->getRanges());
if (auto *MSC = dyn_cast<MaskedScatterSDNode>(N)) {
SDValue OpsLo[] = {Ch, DataLo, MaskLo, Ptr, IndexLo, Ops.Scale};
Lo =
DAG.getMaskedScatter(DAG.getVTList(MVT::Other), LoMemVT, DL, OpsLo, MMO,
MSC->getIndexType(), MSC->isTruncatingStore());
SDValue OpsHi[] = {Lo, DataHi, MaskHi, Ptr, IndexHi, Ops.Scale};
return DAG.getMaskedScatter(DAG.getVTList(MVT::Other), HiMemVT, DL, OpsHi,
MMO, MSC->getIndexType(),
MSC->isTruncatingStore());
}
auto *VPSC = cast<VPScatterSDNode>(N);
SDValue EVLLo, EVLHi;
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(VPSC->getVectorLength(), Ops.Data.getValueType(), DL);
SDValue OpsLo[] = {Ch, DataLo, Ptr, IndexLo, Ops.Scale, MaskLo, EVLLo};
Lo = DAG.getScatterVP(DAG.getVTList(MVT::Other), LoMemVT, DL, OpsLo, MMO,
VPSC->getIndexType());
SDValue OpsHi[] = {Lo, DataHi, Ptr, IndexHi, Ops.Scale, MaskHi, EVLHi};
return DAG.getScatterVP(DAG.getVTList(MVT::Other), HiMemVT, DL, OpsHi, MMO,
VPSC->getIndexType());
}
SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) {
assert(N->isUnindexed() && "Indexed store of vector?");
assert(OpNo == 1 && "Can only split the stored value");
SDLoc DL(N);
bool isTruncating = N->isTruncatingStore();
SDValue Ch = N->getChain();
SDValue Ptr = N->getBasePtr();
EVT MemoryVT = N->getMemoryVT();
Align Alignment = N->getOriginalAlign();
MachineMemOperand::Flags MMOFlags = N->getMemOperand()->getFlags();
AAMDNodes AAInfo = N->getAAInfo();
SDValue Lo, Hi;
GetSplitVector(N->getOperand(1), Lo, Hi);
EVT LoMemVT, HiMemVT;
std::tie(LoMemVT, HiMemVT) = DAG.GetSplitDestVTs(MemoryVT);
if (!LoMemVT.isByteSized() || !HiMemVT.isByteSized())
return TLI.scalarizeVectorStore(N, DAG);
if (isTruncating)
Lo = DAG.getTruncStore(Ch, DL, Lo, Ptr, N->getPointerInfo(), LoMemVT,
Alignment, MMOFlags, AAInfo);
else
Lo = DAG.getStore(Ch, DL, Lo, Ptr, N->getPointerInfo(), Alignment, MMOFlags,
AAInfo);
MachinePointerInfo MPI;
IncrementPointer(N, LoMemVT, MPI, Ptr);
if (isTruncating)
Hi = DAG.getTruncStore(Ch, DL, Hi, Ptr, MPI,
HiMemVT, Alignment, MMOFlags, AAInfo);
else
Hi = DAG.getStore(Ch, DL, Hi, Ptr, MPI, Alignment, MMOFlags, AAInfo);
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi);
}
SDValue DAGTypeLegalizer::SplitVecOp_CONCAT_VECTORS(SDNode *N) {
SDLoc DL(N);
SmallVector<SDValue, 32> Elts;
EVT EltVT = N->getValueType(0).getVectorElementType();
for (const SDValue &Op : N->op_values()) {
for (unsigned i = 0, e = Op.getValueType().getVectorNumElements();
i != e; ++i) {
Elts.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, Op,
DAG.getVectorIdxConstant(i, DL)));
}
}
return DAG.getBuildVector(N->getValueType(0), DL, Elts);
}
SDValue DAGTypeLegalizer::SplitVecOp_TruncateHelper(SDNode *N) {
unsigned OpNo = N->isStrictFPOpcode() ? 1 : 0;
SDValue InVec = N->getOperand(OpNo);
EVT InVT = InVec->getValueType(0);
EVT OutVT = N->getValueType(0);
ElementCount NumElements = OutVT.getVectorElementCount();
bool IsFloat = OutVT.isFloatingPoint();
unsigned InElementSize = InVT.getScalarSizeInBits();
unsigned OutElementSize = OutVT.getScalarSizeInBits();
EVT LoOutVT, HiOutVT;
std::tie(LoOutVT, HiOutVT) = DAG.GetSplitDestVTs(OutVT);
assert(LoOutVT == HiOutVT && "Unequal split?");
if (isTypeLegal(LoOutVT) ||
InElementSize <= OutElementSize * 2)
return SplitVecOp_UnaryOp(N);
SDLoc DL(N);
EVT FinalVT = InVT;
while (getTypeAction(FinalVT) == TargetLowering::TypeSplitVector)
FinalVT = FinalVT.getHalfNumVectorElementsVT(*DAG.getContext());
if (getTypeAction(FinalVT) == TargetLowering::TypeScalarizeVector)
return SplitVecOp_UnaryOp(N);
SDValue InLoVec, InHiVec;
GetSplitVector(InVec, InLoVec, InHiVec);
EVT HalfElementVT = IsFloat ?
EVT::getFloatingPointVT(InElementSize/2) :
EVT::getIntegerVT(*DAG.getContext(), InElementSize/2);
EVT HalfVT = EVT::getVectorVT(*DAG.getContext(), HalfElementVT,
NumElements.divideCoefficientBy(2));
SDValue HalfLo;
SDValue HalfHi;
SDValue Chain;
if (N->isStrictFPOpcode()) {
HalfLo = DAG.getNode(N->getOpcode(), DL, {HalfVT, MVT::Other},
{N->getOperand(0), InLoVec});
HalfHi = DAG.getNode(N->getOpcode(), DL, {HalfVT, MVT::Other},
{N->getOperand(0), InHiVec});
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, HalfLo.getValue(1),
HalfHi.getValue(1));
} else {
HalfLo = DAG.getNode(N->getOpcode(), DL, HalfVT, InLoVec);
HalfHi = DAG.getNode(N->getOpcode(), DL, HalfVT, InHiVec);
}
EVT InterVT = EVT::getVectorVT(*DAG.getContext(), HalfElementVT, NumElements);
SDValue InterVec = DAG.getNode(ISD::CONCAT_VECTORS, DL, InterVT, HalfLo,
HalfHi);
if (N->isStrictFPOpcode()) {
SDValue Res = DAG.getNode(
ISD::STRICT_FP_ROUND, DL, {OutVT, MVT::Other},
{Chain, InterVec,
DAG.getTargetConstant(0, DL, TLI.getPointerTy(DAG.getDataLayout()))});
ReplaceValueWith(SDValue(N, 1), SDValue(Res.getNode(), 1));
return Res;
}
return IsFloat
? DAG.getNode(ISD::FP_ROUND, DL, OutVT, InterVec,
DAG.getTargetConstant(
0, DL, TLI.getPointerTy(DAG.getDataLayout())))
: DAG.getNode(ISD::TRUNCATE, DL, OutVT, InterVec);
}
SDValue DAGTypeLegalizer::SplitVecOp_VSETCC(SDNode *N) {
assert(N->getValueType(0).isVector() &&
N->getOperand(0).getValueType().isVector() &&
"Operand types must be vectors");
SDValue Lo0, Hi0, Lo1, Hi1, LoRes, HiRes;
SDLoc DL(N);
GetSplitVector(N->getOperand(0), Lo0, Hi0);
GetSplitVector(N->getOperand(1), Lo1, Hi1);
auto PartEltCnt = Lo0.getValueType().getVectorElementCount();
LLVMContext &Context = *DAG.getContext();
EVT PartResVT = EVT::getVectorVT(Context, MVT::i1, PartEltCnt);
EVT WideResVT = EVT::getVectorVT(Context, MVT::i1, PartEltCnt*2);
if (N->getOpcode() == ISD::SETCC) {
LoRes = DAG.getNode(ISD::SETCC, DL, PartResVT, Lo0, Lo1, N->getOperand(2));
HiRes = DAG.getNode(ISD::SETCC, DL, PartResVT, Hi0, Hi1, N->getOperand(2));
} else {
assert(N->getOpcode() == ISD::VP_SETCC && "Expected VP_SETCC opcode");
SDValue MaskLo, MaskHi, EVLLo, EVLHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(3));
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(4), N->getValueType(0), DL);
LoRes = DAG.getNode(ISD::VP_SETCC, DL, PartResVT, Lo0, Lo1,
N->getOperand(2), MaskLo, EVLLo);
HiRes = DAG.getNode(ISD::VP_SETCC, DL, PartResVT, Hi0, Hi1,
N->getOperand(2), MaskHi, EVLHi);
}
SDValue Con = DAG.getNode(ISD::CONCAT_VECTORS, DL, WideResVT, LoRes, HiRes);
EVT OpVT = N->getOperand(0).getValueType();
ISD::NodeType ExtendCode =
TargetLowering::getExtendForContent(TLI.getBooleanContents(OpVT));
return DAG.getNode(ExtendCode, DL, N->getValueType(0), Con);
}
SDValue DAGTypeLegalizer::SplitVecOp_FP_ROUND(SDNode *N) {
EVT ResVT = N->getValueType(0);
SDValue Lo, Hi;
SDLoc DL(N);
GetSplitVector(N->getOperand(N->isStrictFPOpcode() ? 1 : 0), Lo, Hi);
EVT InVT = Lo.getValueType();
EVT OutVT = EVT::getVectorVT(*DAG.getContext(), ResVT.getVectorElementType(),
InVT.getVectorElementCount());
if (N->isStrictFPOpcode()) {
Lo = DAG.getNode(N->getOpcode(), DL, { OutVT, MVT::Other },
{ N->getOperand(0), Lo, N->getOperand(2) });
Hi = DAG.getNode(N->getOpcode(), DL, { OutVT, MVT::Other },
{ N->getOperand(0), Hi, N->getOperand(2) });
SDValue NewChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other,
Lo.getValue(1), Hi.getValue(1));
ReplaceValueWith(SDValue(N, 1), NewChain);
} else if (N->getOpcode() == ISD::VP_FP_ROUND) {
SDValue MaskLo, MaskHi, EVLLo, EVLHi;
std::tie(MaskLo, MaskHi) = SplitMask(N->getOperand(1));
std::tie(EVLLo, EVLHi) =
DAG.SplitEVL(N->getOperand(2), N->getValueType(0), DL);
Lo = DAG.getNode(ISD::VP_FP_ROUND, DL, OutVT, Lo, MaskLo, EVLLo);
Hi = DAG.getNode(ISD::VP_FP_ROUND, DL, OutVT, Hi, MaskHi, EVLHi);
} else {
Lo = DAG.getNode(ISD::FP_ROUND, DL, OutVT, Lo, N->getOperand(1));
Hi = DAG.getNode(ISD::FP_ROUND, DL, OutVT, Hi, N->getOperand(1));
}
return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
}
SDValue DAGTypeLegalizer::SplitVecOp_FCOPYSIGN(SDNode *N) {
return DAG.UnrollVectorOp(N, N->getValueType(0).getVectorNumElements());
}
SDValue DAGTypeLegalizer::SplitVecOp_FP_TO_XINT_SAT(SDNode *N) {
EVT ResVT = N->getValueType(0);
SDValue Lo, Hi;
SDLoc dl(N);
GetSplitVector(N->getOperand(0), Lo, Hi);
EVT InVT = Lo.getValueType();
EVT NewResVT =
EVT::getVectorVT(*DAG.getContext(), ResVT.getVectorElementType(),
InVT.getVectorElementCount());
Lo = DAG.getNode(N->getOpcode(), dl, NewResVT, Lo, N->getOperand(1));
Hi = DAG.getNode(N->getOpcode(), dl, NewResVT, Hi, N->getOperand(1));
return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResVT, Lo, Hi);
}
void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
LLVM_DEBUG(dbgs() << "Widen node result " << ResNo << ": "; N->dump(&DAG);
dbgs() << "\n");
if (CustomWidenLowerNode(N, N->getValueType(ResNo)))
return;
SDValue Res = SDValue();
auto unrollExpandedOp = [&]() {
EVT VT = N->getValueType(0);
EVT WideVecVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
if (!TLI.isOperationLegalOrCustom(N->getOpcode(), WideVecVT) &&
TLI.isOperationExpand(N->getOpcode(), VT.getScalarType())) {
Res = DAG.UnrollVectorOp(N, WideVecVT.getVectorNumElements());
return true;
}
return false;
};
switch (N->getOpcode()) {
default:
#ifndef NDEBUG
dbgs() << "WidenVectorResult #" << ResNo << ": ";
N->dump(&DAG);
dbgs() << "\n";
#endif
llvm_unreachable("Do not know how to widen the result of this operator!");
case ISD::MERGE_VALUES: Res = WidenVecRes_MERGE_VALUES(N, ResNo); break;
case ISD::BITCAST: Res = WidenVecRes_BITCAST(N); break;
case ISD::BUILD_VECTOR: Res = WidenVecRes_BUILD_VECTOR(N); break;
case ISD::CONCAT_VECTORS: Res = WidenVecRes_CONCAT_VECTORS(N); break;
case ISD::INSERT_SUBVECTOR:
Res = WidenVecRes_INSERT_SUBVECTOR(N);
break;
case ISD::EXTRACT_SUBVECTOR: Res = WidenVecRes_EXTRACT_SUBVECTOR(N); break;
case ISD::INSERT_VECTOR_ELT: Res = WidenVecRes_INSERT_VECTOR_ELT(N); break;
case ISD::LOAD: Res = WidenVecRes_LOAD(N); break;
case ISD::STEP_VECTOR:
case ISD::SPLAT_VECTOR:
case ISD::SCALAR_TO_VECTOR:
Res = WidenVecRes_ScalarOp(N);
break;
case ISD::SIGN_EXTEND_INREG: Res = WidenVecRes_InregOp(N); break;
case ISD::VSELECT:
case ISD::SELECT:
case ISD::VP_SELECT:
case ISD::VP_MERGE:
Res = WidenVecRes_Select(N);
break;
case ISD::SELECT_CC: Res = WidenVecRes_SELECT_CC(N); break;
case ISD::VP_SETCC:
case ISD::SETCC: Res = WidenVecRes_SETCC(N); break;
case ISD::UNDEF: Res = WidenVecRes_UNDEF(N); break;
case ISD::VECTOR_SHUFFLE:
Res = WidenVecRes_VECTOR_SHUFFLE(cast<ShuffleVectorSDNode>(N));
break;
case ISD::VP_LOAD:
Res = WidenVecRes_VP_LOAD(cast<VPLoadSDNode>(N));
break;
case ISD::MLOAD:
Res = WidenVecRes_MLOAD(cast<MaskedLoadSDNode>(N));
break;
case ISD::MGATHER:
Res = WidenVecRes_MGATHER(cast<MaskedGatherSDNode>(N));
break;
case ISD::VP_GATHER:
Res = WidenVecRes_VP_GATHER(cast<VPGatherSDNode>(N));
break;
case ISD::ADD: case ISD::VP_ADD:
case ISD::AND: case ISD::VP_AND:
case ISD::MUL: case ISD::VP_MUL:
case ISD::MULHS:
case ISD::MULHU:
case ISD::OR: case ISD::VP_OR:
case ISD::SUB: case ISD::VP_SUB:
case ISD::XOR: case ISD::VP_XOR:
case ISD::SHL: case ISD::VP_SHL:
case ISD::SRA: case ISD::VP_ASHR:
case ISD::SRL: case ISD::VP_LSHR:
case ISD::FMINNUM:
case ISD::FMAXNUM:
case ISD::FMINIMUM:
case ISD::FMAXIMUM:
case ISD::SMIN:
case ISD::SMAX:
case ISD::UMIN:
case ISD::UMAX:
case ISD::UADDSAT:
case ISD::SADDSAT:
case ISD::USUBSAT:
case ISD::SSUBSAT:
case ISD::SSHLSAT:
case ISD::USHLSAT:
case ISD::ROTL:
case ISD::ROTR:
case ISD::AVGFLOORS:
case ISD::AVGFLOORU:
case ISD::AVGCEILS:
case ISD::AVGCEILU:
case ISD::VP_SDIV:
case ISD::VP_UDIV:
case ISD::VP_SREM:
case ISD::VP_UREM:
case ISD::VP_FADD:
case ISD::VP_FSUB:
case ISD::VP_FMUL:
case ISD::VP_FDIV:
case ISD::VP_FREM:
Res = WidenVecRes_Binary(N);
break;
case ISD::FPOW:
case ISD::FREM:
if (unrollExpandedOp())
break;
LLVM_FALLTHROUGH;
case ISD::FADD:
case ISD::FMUL:
case ISD::FSUB:
case ISD::FDIV:
case ISD::SDIV:
case ISD::UDIV:
case ISD::SREM:
case ISD::UREM:
Res = WidenVecRes_BinaryCanTrap(N);
break;
case ISD::SMULFIX:
case ISD::SMULFIXSAT:
case ISD::UMULFIX:
case ISD::UMULFIXSAT:
Res = WidenVecRes_BinaryWithExtraScalarOp(N);
break;
#define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \
case ISD::STRICT_##DAGN:
#include "llvm/IR/ConstrainedOps.def"
Res = WidenVecRes_StrictFP(N);
break;
case ISD::UADDO:
case ISD::SADDO:
case ISD::USUBO:
case ISD::SSUBO:
case ISD::UMULO:
case ISD::SMULO:
Res = WidenVecRes_OverflowOp(N, ResNo);
break;
case ISD::FCOPYSIGN:
Res = WidenVecRes_FCOPYSIGN(N);
break;
case ISD::IS_FPCLASS:
Res = WidenVecRes_IS_FPCLASS(N);
break;
case ISD::FPOWI:
Res = WidenVecRes_POWI(N);
break;
case ISD::ANY_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
Res = WidenVecRes_EXTEND_VECTOR_INREG(N);
break;
case ISD::ANY_EXTEND:
case ISD::FP_EXTEND:
case ISD::VP_FP_EXTEND:
case ISD::FP_ROUND:
case ISD::VP_FP_ROUND:
case ISD::FP_TO_SINT:
case ISD::VP_FPTOSI:
case ISD::FP_TO_UINT:
case ISD::VP_FPTOUI:
case ISD::SIGN_EXTEND:
case ISD::VP_SIGN_EXTEND:
case ISD::SINT_TO_FP:
case ISD::VP_SITOFP:
case ISD::VP_TRUNCATE:
case ISD::TRUNCATE:
case ISD::UINT_TO_FP:
case ISD::VP_UITOFP:
case ISD::ZERO_EXTEND:
case ISD::VP_ZERO_EXTEND:
Res = WidenVecRes_Convert(N);
break;
case ISD::FP_TO_SINT_SAT:
case ISD::FP_TO_UINT_SAT:
Res = WidenVecRes_FP_TO_XINT_SAT(N);
break;
case ISD::FABS:
case ISD::FCEIL:
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG10:
case ISD::FLOG2:
case ISD::FNEARBYINT:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
if (unrollExpandedOp())
break;
LLVM_FALLTHROUGH;
case ISD::ABS:
case ISD::BITREVERSE:
case ISD::BSWAP:
case ISD::CTLZ:
case ISD::CTLZ_ZERO_UNDEF:
case ISD::CTPOP:
case ISD::CTTZ:
case ISD::CTTZ_ZERO_UNDEF:
case ISD::FNEG: case ISD::VP_FNEG:
case ISD::FREEZE:
case ISD::ARITH_FENCE:
case ISD::FCANONICALIZE:
Res = WidenVecRes_Unary(N);
break;
case ISD::FMA: case ISD::VP_FMA:
case ISD::FSHL:
case ISD::FSHR:
Res = WidenVecRes_Ternary(N);
break;
}
if (Res.getNode())
SetWidenedVector(SDValue(N, ResNo), Res);
}
SDValue DAGTypeLegalizer::WidenVecRes_Ternary(SDNode *N) {
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = GetWidenedVector(N->getOperand(1));
SDValue InOp3 = GetWidenedVector(N->getOperand(2));
if (N->getNumOperands() == 3)
return DAG.getNode(N->getOpcode(), dl, WidenVT, InOp1, InOp2, InOp3);
assert(N->getNumOperands() == 5 && "Unexpected number of operands!");
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue Mask =
GetWidenedMask(N->getOperand(3), WidenVT.getVectorElementCount());
return DAG.getNode(N->getOpcode(), dl, WidenVT,
{InOp1, InOp2, InOp3, Mask, N->getOperand(4)});
}
SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) {
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = GetWidenedVector(N->getOperand(1));
if (N->getNumOperands() == 2)
return DAG.getNode(N->getOpcode(), dl, WidenVT, InOp1, InOp2,
N->getFlags());
assert(N->getNumOperands() == 4 && "Unexpected number of operands!");
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue Mask =
GetWidenedMask(N->getOperand(2), WidenVT.getVectorElementCount());
return DAG.getNode(N->getOpcode(), dl, WidenVT,
{InOp1, InOp2, Mask, N->getOperand(3)}, N->getFlags());
}
SDValue DAGTypeLegalizer::WidenVecRes_BinaryWithExtraScalarOp(SDNode *N) {
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = GetWidenedVector(N->getOperand(1));
SDValue InOp3 = N->getOperand(2);
return DAG.getNode(N->getOpcode(), dl, WidenVT, InOp1, InOp2, InOp3,
N->getFlags());
}
static SDValue CollectOpsToWiden(SelectionDAG &DAG, const TargetLowering &TLI,
SmallVectorImpl<SDValue> &ConcatOps,
unsigned ConcatEnd, EVT VT, EVT MaxVT,
EVT WidenVT) {
if (ConcatEnd == 1) {
VT = ConcatOps[0].getValueType();
if (VT == WidenVT)
return ConcatOps[0];
}
SDLoc dl(ConcatOps[0]);
EVT WidenEltVT = WidenVT.getVectorElementType();
while (ConcatOps[ConcatEnd-1].getValueType() != MaxVT) {
int Idx = ConcatEnd - 1;
VT = ConcatOps[Idx--].getValueType();
while (Idx >= 0 && ConcatOps[Idx].getValueType() == VT)
Idx--;
int NextSize = VT.isVector() ? VT.getVectorNumElements() : 1;
EVT NextVT;
do {
NextSize *= 2;
NextVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NextSize);
} while (!TLI.isTypeLegal(NextVT));
if (!VT.isVector()) {
SDValue VecOp = DAG.getUNDEF(NextVT);
unsigned NumToInsert = ConcatEnd - Idx - 1;
for (unsigned i = 0, OpIdx = Idx+1; i < NumToInsert; i++, OpIdx++) {
VecOp = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NextVT, VecOp,
ConcatOps[OpIdx], DAG.getVectorIdxConstant(i, dl));
}
ConcatOps[Idx+1] = VecOp;
ConcatEnd = Idx + 2;
} else {
SDValue undefVec = DAG.getUNDEF(VT);
unsigned OpsToConcat = NextSize/VT.getVectorNumElements();
SmallVector<SDValue, 16> SubConcatOps(OpsToConcat);
unsigned RealVals = ConcatEnd - Idx - 1;
unsigned SubConcatEnd = 0;
unsigned SubConcatIdx = Idx + 1;
while (SubConcatEnd < RealVals)
SubConcatOps[SubConcatEnd++] = ConcatOps[++Idx];
while (SubConcatEnd < OpsToConcat)
SubConcatOps[SubConcatEnd++] = undefVec;
ConcatOps[SubConcatIdx] = DAG.getNode(ISD::CONCAT_VECTORS, dl,
NextVT, SubConcatOps);
ConcatEnd = SubConcatIdx + 1;
}
}
if (ConcatEnd == 1) {
VT = ConcatOps[0].getValueType();
if (VT == WidenVT)
return ConcatOps[0];
}
unsigned NumOps = WidenVT.getVectorNumElements()/MaxVT.getVectorNumElements();
if (NumOps != ConcatEnd ) {
SDValue UndefVal = DAG.getUNDEF(MaxVT);
for (unsigned j = ConcatEnd; j < NumOps; ++j)
ConcatOps[j] = UndefVal;
}
return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT,
makeArrayRef(ConcatOps.data(), NumOps));
}
SDValue DAGTypeLegalizer::WidenVecRes_BinaryCanTrap(SDNode *N) {
unsigned Opcode = N->getOpcode();
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
EVT WidenEltVT = WidenVT.getVectorElementType();
EVT VT = WidenVT;
unsigned NumElts = VT.getVectorMinNumElements();
const SDNodeFlags Flags = N->getFlags();
while (!TLI.isTypeLegal(VT) && NumElts != 1) {
NumElts = NumElts / 2;
VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts);
}
if (NumElts != 1 && !TLI.canOpTrap(N->getOpcode(), VT)) {
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = GetWidenedVector(N->getOperand(1));
return DAG.getNode(N->getOpcode(), dl, WidenVT, InOp1, InOp2, Flags);
}
assert(!VT.isScalableVector() && "Scalable vectors not handled yet.");
if (NumElts == 1)
return DAG.UnrollVectorOp(N, WidenVT.getVectorNumElements());
EVT MaxVT = VT;
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = GetWidenedVector(N->getOperand(1));
unsigned CurNumElts = N->getValueType(0).getVectorNumElements();
SmallVector<SDValue, 16> ConcatOps(CurNumElts);
unsigned ConcatEnd = 0; int Idx = 0;
while (CurNumElts != 0) {
while (CurNumElts >= NumElts) {
SDValue EOp1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, InOp1,
DAG.getVectorIdxConstant(Idx, dl));
SDValue EOp2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, InOp2,
DAG.getVectorIdxConstant(Idx, dl));
ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, VT, EOp1, EOp2, Flags);
Idx += NumElts;
CurNumElts -= NumElts;
}
do {
NumElts = NumElts / 2;
VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts);
} while (!TLI.isTypeLegal(VT) && NumElts != 1);
if (NumElts == 1) {
for (unsigned i = 0; i != CurNumElts; ++i, ++Idx) {
SDValue EOp1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT,
InOp1, DAG.getVectorIdxConstant(Idx, dl));
SDValue EOp2 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT,
InOp2, DAG.getVectorIdxConstant(Idx, dl));
ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, WidenEltVT,
EOp1, EOp2, Flags);
}
CurNumElts = 0;
}
}
return CollectOpsToWiden(DAG, TLI, ConcatOps, ConcatEnd, VT, MaxVT, WidenVT);
}
SDValue DAGTypeLegalizer::WidenVecRes_StrictFP(SDNode *N) {
switch (N->getOpcode()) {
case ISD::STRICT_FSETCC:
case ISD::STRICT_FSETCCS:
return WidenVecRes_STRICT_FSETCC(N);
case ISD::STRICT_FP_EXTEND:
case ISD::STRICT_FP_ROUND:
case ISD::STRICT_FP_TO_SINT:
case ISD::STRICT_FP_TO_UINT:
case ISD::STRICT_SINT_TO_FP:
case ISD::STRICT_UINT_TO_FP:
return WidenVecRes_Convert_StrictFP(N);
default:
break;
}
unsigned NumOpers = N->getNumOperands();
unsigned Opcode = N->getOpcode();
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
EVT WidenEltVT = WidenVT.getVectorElementType();
EVT VT = WidenVT;
unsigned NumElts = VT.getVectorNumElements();
while (!TLI.isTypeLegal(VT) && NumElts != 1) {
NumElts = NumElts / 2;
VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts);
}
if (NumElts == 1)
return UnrollVectorOp_StrictFP(N, WidenVT.getVectorNumElements());
EVT MaxVT = VT;
SmallVector<SDValue, 4> InOps;
unsigned CurNumElts = N->getValueType(0).getVectorNumElements();
SmallVector<SDValue, 16> ConcatOps(CurNumElts);
SmallVector<SDValue, 16> Chains;
unsigned ConcatEnd = 0; int Idx = 0;
InOps.push_back(N->getOperand(0));
for (unsigned i = 1; i < NumOpers; ++i) {
SDValue Oper = N->getOperand(i);
if (Oper.getValueType().isVector()) {
assert(Oper.getValueType() == N->getValueType(0) &&
"Invalid operand type to widen!");
Oper = GetWidenedVector(Oper);
}
InOps.push_back(Oper);
}
while (CurNumElts != 0) {
while (CurNumElts >= NumElts) {
SmallVector<SDValue, 4> EOps;
for (unsigned i = 0; i < NumOpers; ++i) {
SDValue Op = InOps[i];
if (Op.getValueType().isVector())
Op = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, Op,
DAG.getVectorIdxConstant(Idx, dl));
EOps.push_back(Op);
}
EVT OperVT[] = {VT, MVT::Other};
SDValue Oper = DAG.getNode(Opcode, dl, OperVT, EOps);
ConcatOps[ConcatEnd++] = Oper;
Chains.push_back(Oper.getValue(1));
Idx += NumElts;
CurNumElts -= NumElts;
}
do {
NumElts = NumElts / 2;
VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts);
} while (!TLI.isTypeLegal(VT) && NumElts != 1);
if (NumElts == 1) {
for (unsigned i = 0; i != CurNumElts; ++i, ++Idx) {
SmallVector<SDValue, 4> EOps;
for (unsigned i = 0; i < NumOpers; ++i) {
SDValue Op = InOps[i];
if (Op.getValueType().isVector())
Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, Op,
DAG.getVectorIdxConstant(Idx, dl));
EOps.push_back(Op);
}
EVT WidenVT[] = {WidenEltVT, MVT::Other};
SDValue Oper = DAG.getNode(Opcode, dl, WidenVT, EOps);
ConcatOps[ConcatEnd++] = Oper;
Chains.push_back(Oper.getValue(1));
}
CurNumElts = 0;
}
}
SDValue NewChain;
if (Chains.size() == 1)
NewChain = Chains[0];
else
NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Chains);
ReplaceValueWith(SDValue(N, 1), NewChain);
return CollectOpsToWiden(DAG, TLI, ConcatOps, ConcatEnd, VT, MaxVT, WidenVT);
}
SDValue DAGTypeLegalizer::WidenVecRes_OverflowOp(SDNode *N, unsigned ResNo) {
SDLoc DL(N);
EVT ResVT = N->getValueType(0);
EVT OvVT = N->getValueType(1);
EVT WideResVT, WideOvVT;
SDValue WideLHS, WideRHS;
if (ResNo == 0) {
WideResVT = TLI.getTypeToTransformTo(*DAG.getContext(), ResVT);
WideOvVT = EVT::getVectorVT(
*DAG.getContext(), OvVT.getVectorElementType(),
WideResVT.getVectorNumElements());
WideLHS = GetWidenedVector(N->getOperand(0));
WideRHS = GetWidenedVector(N->getOperand(1));
} else {
WideOvVT = TLI.getTypeToTransformTo(*DAG.getContext(), OvVT);
WideResVT = EVT::getVectorVT(
*DAG.getContext(), ResVT.getVectorElementType(),
WideOvVT.getVectorNumElements());
SDValue Zero = DAG.getVectorIdxConstant(0, DL);
WideLHS = DAG.getNode(
ISD::INSERT_SUBVECTOR, DL, WideResVT, DAG.getUNDEF(WideResVT),
N->getOperand(0), Zero);
WideRHS = DAG.getNode(
ISD::INSERT_SUBVECTOR, DL, WideResVT, DAG.getUNDEF(WideResVT),
N->getOperand(1), Zero);
}
SDVTList WideVTs = DAG.getVTList(WideResVT, WideOvVT);
SDNode *WideNode = DAG.getNode(
N->getOpcode(), DL, WideVTs, WideLHS, WideRHS).getNode();
unsigned OtherNo = 1 - ResNo;
EVT OtherVT = N->getValueType(OtherNo);
if (getTypeAction(OtherVT) == TargetLowering::TypeWidenVector) {
SetWidenedVector(SDValue(N, OtherNo), SDValue(WideNode, OtherNo));
} else {
SDValue Zero = DAG.getVectorIdxConstant(0, DL);
SDValue OtherVal = DAG.getNode(
ISD::EXTRACT_SUBVECTOR, DL, OtherVT, SDValue(WideNode, OtherNo), Zero);
ReplaceValueWith(SDValue(N, OtherNo), OtherVal);
}
return SDValue(WideNode, ResNo);
}
SDValue DAGTypeLegalizer::WidenVecRes_Convert(SDNode *N) {
LLVMContext &Ctx = *DAG.getContext();
SDValue InOp = N->getOperand(0);
SDLoc DL(N);
EVT WidenVT = TLI.getTypeToTransformTo(Ctx, N->getValueType(0));
ElementCount WidenEC = WidenVT.getVectorElementCount();
EVT InVT = InOp.getValueType();
unsigned Opcode = N->getOpcode();
const SDNodeFlags Flags = N->getFlags();
if (N->getOpcode() == ISD::ZERO_EXTEND &&
getTypeAction(InVT) == TargetLowering::TypePromoteInteger &&
TLI.getTypeToTransformTo(Ctx, InVT).getScalarSizeInBits() !=
WidenVT.getScalarSizeInBits()) {
InOp = ZExtPromotedInteger(InOp);
InVT = InOp.getValueType();
if (WidenVT.getScalarSizeInBits() < InVT.getScalarSizeInBits())
Opcode = ISD::TRUNCATE;
}
EVT InEltVT = InVT.getVectorElementType();
EVT InWidenVT = EVT::getVectorVT(Ctx, InEltVT, WidenEC);
ElementCount InVTEC = InVT.getVectorElementCount();
if (getTypeAction(InVT) == TargetLowering::TypeWidenVector) {
InOp = GetWidenedVector(N->getOperand(0));
InVT = InOp.getValueType();
InVTEC = InVT.getVectorElementCount();
if (InVTEC == WidenEC) {
if (N->getNumOperands() == 1)
return DAG.getNode(Opcode, DL, WidenVT, InOp);
if (N->getNumOperands() == 3) {
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue Mask =
GetWidenedMask(N->getOperand(1), WidenVT.getVectorElementCount());
return DAG.getNode(Opcode, DL, WidenVT, InOp, Mask, N->getOperand(2));
}
return DAG.getNode(Opcode, DL, WidenVT, InOp, N->getOperand(1), Flags);
}
if (WidenVT.getSizeInBits() == InVT.getSizeInBits()) {
if (Opcode == ISD::ANY_EXTEND)
return DAG.getNode(ISD::ANY_EXTEND_VECTOR_INREG, DL, WidenVT, InOp);
if (Opcode == ISD::SIGN_EXTEND)
return DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, WidenVT, InOp);
if (Opcode == ISD::ZERO_EXTEND)
return DAG.getNode(ISD::ZERO_EXTEND_VECTOR_INREG, DL, WidenVT, InOp);
}
}
if (TLI.isTypeLegal(InWidenVT)) {
if (WidenEC.isKnownMultipleOf(InVTEC.getKnownMinValue())) {
unsigned NumConcat =
WidenEC.getKnownMinValue() / InVTEC.getKnownMinValue();
SmallVector<SDValue, 16> Ops(NumConcat, DAG.getUNDEF(InVT));
Ops[0] = InOp;
SDValue InVec = DAG.getNode(ISD::CONCAT_VECTORS, DL, InWidenVT, Ops);
if (N->getNumOperands() == 1)
return DAG.getNode(Opcode, DL, WidenVT, InVec);
return DAG.getNode(Opcode, DL, WidenVT, InVec, N->getOperand(1), Flags);
}
if (InVTEC.isKnownMultipleOf(WidenEC.getKnownMinValue())) {
SDValue InVal = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, InWidenVT, InOp,
DAG.getVectorIdxConstant(0, DL));
if (N->getNumOperands() == 1)
return DAG.getNode(Opcode, DL, WidenVT, InVal);
return DAG.getNode(Opcode, DL, WidenVT, InVal, N->getOperand(1), Flags);
}
}
EVT EltVT = WidenVT.getVectorElementType();
SmallVector<SDValue, 16> Ops(WidenEC.getFixedValue(), DAG.getUNDEF(EltVT));
unsigned MinElts = N->getValueType(0).getVectorNumElements();
for (unsigned i=0; i < MinElts; ++i) {
SDValue Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, InEltVT, InOp,
DAG.getVectorIdxConstant(i, DL));
if (N->getNumOperands() == 1)
Ops[i] = DAG.getNode(Opcode, DL, EltVT, Val);
else
Ops[i] = DAG.getNode(Opcode, DL, EltVT, Val, N->getOperand(1), Flags);
}
return DAG.getBuildVector(WidenVT, DL, Ops);
}
SDValue DAGTypeLegalizer::WidenVecRes_FP_TO_XINT_SAT(SDNode *N) {
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
ElementCount WidenNumElts = WidenVT.getVectorElementCount();
SDValue Src = N->getOperand(0);
EVT SrcVT = Src.getValueType();
if (getTypeAction(SrcVT) == TargetLowering::TypeWidenVector) {
Src = GetWidenedVector(Src);
SrcVT = Src.getValueType();
}
if (WidenNumElts != SrcVT.getVectorElementCount())
return DAG.UnrollVectorOp(N, WidenNumElts.getKnownMinValue());
return DAG.getNode(N->getOpcode(), dl, WidenVT, Src, N->getOperand(1));
}
SDValue DAGTypeLegalizer::WidenVecRes_Convert_StrictFP(SDNode *N) {
SDValue InOp = N->getOperand(1);
SDLoc DL(N);
SmallVector<SDValue, 4> NewOps(N->op_begin(), N->op_end());
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
unsigned WidenNumElts = WidenVT.getVectorNumElements();
EVT InVT = InOp.getValueType();
EVT InEltVT = InVT.getVectorElementType();
unsigned Opcode = N->getOpcode();
EVT EltVT = WidenVT.getVectorElementType();
std::array<EVT, 2> EltVTs = {{EltVT, MVT::Other}};
SmallVector<SDValue, 16> Ops(WidenNumElts, DAG.getUNDEF(EltVT));
SmallVector<SDValue, 32> OpChains;
unsigned MinElts = N->getValueType(0).getVectorNumElements();
for (unsigned i=0; i < MinElts; ++i) {
NewOps[1] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, InEltVT, InOp,
DAG.getVectorIdxConstant(i, DL));
Ops[i] = DAG.getNode(Opcode, DL, EltVTs, NewOps);
OpChains.push_back(Ops[i].getValue(1));
}
SDValue NewChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OpChains);
ReplaceValueWith(SDValue(N, 1), NewChain);
return DAG.getBuildVector(WidenVT, DL, Ops);
}
SDValue DAGTypeLegalizer::WidenVecRes_EXTEND_VECTOR_INREG(SDNode *N) {
unsigned Opcode = N->getOpcode();
SDValue InOp = N->getOperand(0);
SDLoc DL(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
EVT WidenSVT = WidenVT.getVectorElementType();
unsigned WidenNumElts = WidenVT.getVectorNumElements();
EVT InVT = InOp.getValueType();
EVT InSVT = InVT.getVectorElementType();
unsigned InVTNumElts = InVT.getVectorNumElements();
if (getTypeAction(InVT) == TargetLowering::TypeWidenVector) {
InOp = GetWidenedVector(InOp);
InVT = InOp.getValueType();
if (InVT.getSizeInBits() == WidenVT.getSizeInBits()) {
switch (Opcode) {
case ISD::ANY_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
return DAG.getNode(Opcode, DL, WidenVT, InOp);
}
}
}
SmallVector<SDValue, 16> Ops;
for (unsigned i = 0, e = std::min(InVTNumElts, WidenNumElts); i != e; ++i) {
SDValue Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, InSVT, InOp,
DAG.getVectorIdxConstant(i, DL));
switch (Opcode) {
case ISD::ANY_EXTEND_VECTOR_INREG:
Val = DAG.getNode(ISD::ANY_EXTEND, DL, WidenSVT, Val);
break;
case ISD::SIGN_EXTEND_VECTOR_INREG:
Val = DAG.getNode(ISD::SIGN_EXTEND, DL, WidenSVT, Val);
break;
case ISD::ZERO_EXTEND_VECTOR_INREG:
Val = DAG.getNode(ISD::ZERO_EXTEND, DL, WidenSVT, Val);
break;
default:
llvm_unreachable("A *_EXTEND_VECTOR_INREG node was expected");
}
Ops.push_back(Val);
}
while (Ops.size() != WidenNumElts)
Ops.push_back(DAG.getUNDEF(WidenSVT));
return DAG.getBuildVector(WidenVT, DL, Ops);
}
SDValue DAGTypeLegalizer::WidenVecRes_FCOPYSIGN(SDNode *N) {
if (N->getOperand(0).getValueType() == N->getOperand(1).getValueType())
return WidenVecRes_BinaryCanTrap(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
return DAG.UnrollVectorOp(N, WidenVT.getVectorNumElements());
}
SDValue DAGTypeLegalizer::WidenVecRes_IS_FPCLASS(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue Arg = GetWidenedVector(N->getOperand(0));
return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, {Arg, N->getOperand(1)},
N->getFlags());
}
SDValue DAGTypeLegalizer::WidenVecRes_POWI(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue InOp = GetWidenedVector(N->getOperand(0));
SDValue ShOp = N->getOperand(1);
return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, InOp, ShOp);
}
SDValue DAGTypeLegalizer::WidenVecRes_Unary(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue InOp = GetWidenedVector(N->getOperand(0));
if (N->getNumOperands() == 1)
return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, InOp);
assert(N->getNumOperands() == 3 && "Unexpected number of operands!");
assert(N->isVPOpcode() && "Expected VP opcode");
SDValue Mask =
GetWidenedMask(N->getOperand(1), WidenVT.getVectorElementCount());
return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT,
{InOp, Mask, N->getOperand(2)});
}
SDValue DAGTypeLegalizer::WidenVecRes_InregOp(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
EVT ExtVT = EVT::getVectorVT(*DAG.getContext(),
cast<VTSDNode>(N->getOperand(1))->getVT()
.getVectorElementType(),
WidenVT.getVectorNumElements());
SDValue WidenLHS = GetWidenedVector(N->getOperand(0));
return DAG.getNode(N->getOpcode(), SDLoc(N),
WidenVT, WidenLHS, DAG.getValueType(ExtVT));
}
SDValue DAGTypeLegalizer::WidenVecRes_MERGE_VALUES(SDNode *N, unsigned ResNo) {
SDValue WidenVec = DisintegrateMERGE_VALUES(N, ResNo);
return GetWidenedVector(WidenVec);
}
SDValue DAGTypeLegalizer::WidenVecRes_BITCAST(SDNode *N) {
SDValue InOp = N->getOperand(0);
EVT InVT = InOp.getValueType();
EVT VT = N->getValueType(0);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
SDLoc dl(N);
switch (getTypeAction(InVT)) {
case TargetLowering::TypeLegal:
break;
case TargetLowering::TypeScalarizeScalableVector:
report_fatal_error("Scalarization of scalable vectors is not supported.");
case TargetLowering::TypePromoteInteger: {
if (InVT.isVector())
break;
SDValue NInOp = GetPromotedInteger(InOp);
EVT NInVT = NInOp.getValueType();
if (WidenVT.bitsEq(NInVT)) {
if (DAG.getDataLayout().isBigEndian()) {
unsigned ShiftAmt = NInVT.getSizeInBits() - InVT.getSizeInBits();
EVT ShiftAmtTy = TLI.getShiftAmountTy(NInVT, DAG.getDataLayout());
assert(ShiftAmt < WidenVT.getSizeInBits() && "Too large shift amount!");
NInOp = DAG.getNode(ISD::SHL, dl, NInVT, NInOp,
DAG.getConstant(ShiftAmt, dl, ShiftAmtTy));
}
return DAG.getNode(ISD::BITCAST, dl, WidenVT, NInOp);
}
InOp = NInOp;
InVT = NInVT;
break;
}
case TargetLowering::TypeSoftenFloat:
case TargetLowering::TypePromoteFloat:
case TargetLowering::TypeSoftPromoteHalf:
case TargetLowering::TypeExpandInteger:
case TargetLowering::TypeExpandFloat:
case TargetLowering::TypeScalarizeVector:
case TargetLowering::TypeSplitVector:
break;
case TargetLowering::TypeWidenVector:
InOp = GetWidenedVector(InOp);
InVT = InOp.getValueType();
if (WidenVT.bitsEq(InVT))
return DAG.getNode(ISD::BITCAST, dl, WidenVT, InOp);
break;
}
unsigned WidenSize = WidenVT.getSizeInBits();
unsigned InSize = InVT.getSizeInBits();
if (WidenSize % InSize == 0 && InVT != MVT::x86mmx) {
EVT NewInVT;
unsigned NewNumElts = WidenSize / InSize;
if (InVT.isVector()) {
EVT InEltVT = InVT.getVectorElementType();
NewInVT = EVT::getVectorVT(*DAG.getContext(), InEltVT,
WidenSize / InEltVT.getSizeInBits());
} else {
NewInVT = EVT::getVectorVT(*DAG.getContext(), InVT, NewNumElts);
}
if (TLI.isTypeLegal(NewInVT)) {
SDValue NewVec;
if (InVT.isVector()) {
SmallVector<SDValue, 16> Ops(NewNumElts, DAG.getUNDEF(InVT));
Ops[0] = InOp;
NewVec = DAG.getNode(ISD::CONCAT_VECTORS, dl, NewInVT, Ops);
} else {
NewVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, NewInVT, InOp);
}
return DAG.getNode(ISD::BITCAST, dl, WidenVT, NewVec);
}
}
return CreateStackStoreLoad(InOp, WidenVT);
}
SDValue DAGTypeLegalizer::WidenVecRes_BUILD_VECTOR(SDNode *N) {
SDLoc dl(N);
EVT VT = N->getValueType(0);
EVT EltVT = N->getOperand(0).getValueType();
unsigned NumElts = VT.getVectorNumElements();
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
unsigned WidenNumElts = WidenVT.getVectorNumElements();
SmallVector<SDValue, 16> NewOps(N->op_begin(), N->op_end());
assert(WidenNumElts >= NumElts && "Shrinking vector instead of widening!");
NewOps.append(WidenNumElts - NumElts, DAG.getUNDEF(EltVT));
return DAG.getBuildVector(WidenVT, dl, NewOps);
}
SDValue DAGTypeLegalizer::WidenVecRes_CONCAT_VECTORS(SDNode *N) {
EVT InVT = N->getOperand(0).getValueType();
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDLoc dl(N);
unsigned NumOperands = N->getNumOperands();
bool InputWidened = false; if (getTypeAction(InVT) != TargetLowering::TypeWidenVector) {
unsigned WidenNumElts = WidenVT.getVectorMinNumElements();
unsigned NumInElts = InVT.getVectorMinNumElements();
if (WidenNumElts % NumInElts == 0) {
unsigned NumConcat = WidenNumElts / NumInElts;
SDValue UndefVal = DAG.getUNDEF(InVT);
SmallVector<SDValue, 16> Ops(NumConcat);
for (unsigned i=0; i < NumOperands; ++i)
Ops[i] = N->getOperand(i);
for (unsigned i = NumOperands; i != NumConcat; ++i)
Ops[i] = UndefVal;
return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, Ops);
}
} else {
InputWidened = true;
if (WidenVT == TLI.getTypeToTransformTo(*DAG.getContext(), InVT)) {
unsigned i;
for (i=1; i < NumOperands; ++i)
if (!N->getOperand(i).isUndef())
break;
if (i == NumOperands)
return GetWidenedVector(N->getOperand(0));
if (NumOperands == 2) {
assert(!WidenVT.isScalableVector() &&
"Cannot use vector shuffles to widen CONCAT_VECTOR result");
unsigned WidenNumElts = WidenVT.getVectorNumElements();
unsigned NumInElts = InVT.getVectorNumElements();
SmallVector<int, 16> MaskOps(WidenNumElts, -1);
for (unsigned i = 0; i < NumInElts; ++i) {
MaskOps[i] = i;
MaskOps[i + NumInElts] = i + WidenNumElts;
}
return DAG.getVectorShuffle(WidenVT, dl,
GetWidenedVector(N->getOperand(0)),
GetWidenedVector(N->getOperand(1)),
MaskOps);
}
}
}
assert(!WidenVT.isScalableVector() &&
"Cannot use build vectors to widen CONCAT_VECTOR result");
unsigned WidenNumElts = WidenVT.getVectorNumElements();
unsigned NumInElts = InVT.getVectorNumElements();
EVT EltVT = WidenVT.getVectorElementType();
SmallVector<SDValue, 16> Ops(WidenNumElts);
unsigned Idx = 0;
for (unsigned i=0; i < NumOperands; ++i) {
SDValue InOp = N->getOperand(i);
if (InputWidened)
InOp = GetWidenedVector(InOp);
for (unsigned j = 0; j < NumInElts; ++j)
Ops[Idx++] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp,
DAG.getVectorIdxConstant(j, dl));
}
SDValue UndefVal = DAG.getUNDEF(EltVT);
for (; Idx < WidenNumElts; ++Idx)
Ops[Idx] = UndefVal;
return DAG.getBuildVector(WidenVT, dl, Ops);
}
SDValue DAGTypeLegalizer::WidenVecRes_INSERT_SUBVECTOR(SDNode *N) {
EVT VT = N->getValueType(0);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = N->getOperand(1);
SDValue Idx = N->getOperand(2);
SDLoc dl(N);
return DAG.getNode(ISD::INSERT_SUBVECTOR, dl, WidenVT, InOp1, InOp2, Idx);
}
SDValue DAGTypeLegalizer::WidenVecRes_EXTRACT_SUBVECTOR(SDNode *N) {
EVT VT = N->getValueType(0);
EVT EltVT = VT.getVectorElementType();
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
SDValue InOp = N->getOperand(0);
SDValue Idx = N->getOperand(1);
SDLoc dl(N);
auto InOpTypeAction = getTypeAction(InOp.getValueType());
if (InOpTypeAction == TargetLowering::TypeWidenVector)
InOp = GetWidenedVector(InOp);
EVT InVT = InOp.getValueType();
uint64_t IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
if (IdxVal == 0 && InVT == WidenVT)
return InOp;
unsigned WidenNumElts = WidenVT.getVectorMinNumElements();
unsigned InNumElts = InVT.getVectorMinNumElements();
unsigned VTNumElts = VT.getVectorMinNumElements();
assert(IdxVal % VTNumElts == 0 &&
"Expected Idx to be a multiple of subvector minimum vector length");
if (IdxVal % WidenNumElts == 0 && IdxVal + WidenNumElts < InNumElts)
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, WidenVT, InOp, Idx);
if (VT.isScalableVector()) {
unsigned GCD = greatestCommonDivisor(VTNumElts, WidenNumElts);
assert((IdxVal % GCD) == 0 && "Expected Idx to be a multiple of the broken "
"down type's element count");
EVT PartVT = EVT::getVectorVT(*DAG.getContext(), EltVT,
ElementCount::getScalable(GCD));
if (getTypeAction(PartVT) != TargetLowering::TypeWidenVector) {
SmallVector<SDValue> Parts;
unsigned I = 0;
for (; I < VTNumElts / GCD; ++I)
Parts.push_back(
DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, PartVT, InOp,
DAG.getVectorIdxConstant(IdxVal + I * GCD, dl)));
for (; I < WidenNumElts / GCD; ++I)
Parts.push_back(DAG.getUNDEF(PartVT));
return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, Parts);
}
report_fatal_error("Don't know how to widen the result of "
"EXTRACT_SUBVECTOR for scalable vectors");
}
SmallVector<SDValue, 16> Ops(WidenNumElts);
unsigned i;
for (i = 0; i < VTNumElts; ++i)
Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp,
DAG.getVectorIdxConstant(IdxVal + i, dl));
SDValue UndefVal = DAG.getUNDEF(EltVT);
for (; i < WidenNumElts; ++i)
Ops[i] = UndefVal;
return DAG.getBuildVector(WidenVT, dl, Ops);
}
SDValue DAGTypeLegalizer::WidenVecRes_INSERT_VECTOR_ELT(SDNode *N) {
SDValue InOp = GetWidenedVector(N->getOperand(0));
return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N),
InOp.getValueType(), InOp,
N->getOperand(1), N->getOperand(2));
}
SDValue DAGTypeLegalizer::WidenVecRes_LOAD(SDNode *N) {
LoadSDNode *LD = cast<LoadSDNode>(N);
ISD::LoadExtType ExtType = LD->getExtensionType();
if (!LD->getMemoryVT().isByteSized()) {
SDValue Value, NewChain;
std::tie(Value, NewChain) = TLI.scalarizeVectorLoad(LD, DAG);
ReplaceValueWith(SDValue(LD, 0), Value);
ReplaceValueWith(SDValue(LD, 1), NewChain);
return SDValue();
}
SDValue Result;
SmallVector<SDValue, 16> LdChain; if (ExtType != ISD::NON_EXTLOAD)
Result = GenWidenVectorExtLoads(LdChain, LD, ExtType);
else
Result = GenWidenVectorLoads(LdChain, LD);
if (Result) {
SDValue NewChain;
if (LdChain.size() == 1)
NewChain = LdChain[0];
else
NewChain = DAG.getNode(ISD::TokenFactor, SDLoc(LD), MVT::Other, LdChain);
ReplaceValueWith(SDValue(N, 1), NewChain);
return Result;
}
EVT LdVT = LD->getMemoryVT();
EVT WideVT = TLI.getTypeToTransformTo(*DAG.getContext(), LdVT);
EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
WideVT.getVectorElementCount());
if (ExtType == ISD::NON_EXTLOAD && WideVT.isScalableVector() &&
TLI.isOperationLegalOrCustom(ISD::VP_LOAD, WideVT) &&
TLI.isTypeLegal(WideMaskVT)) {
SDLoc DL(N);
SDValue Mask = DAG.getAllOnesConstant(DL, WideMaskVT);
MVT EVLVT = TLI.getVPExplicitVectorLengthTy();
unsigned NumVTElts = LdVT.getVectorMinNumElements();
SDValue EVL =
DAG.getVScale(DL, EVLVT, APInt(EVLVT.getScalarSizeInBits(), NumVTElts));
const auto *MMO = LD->getMemOperand();
SDValue NewLoad =
DAG.getLoadVP(WideVT, DL, LD->getChain(), LD->getBasePtr(), Mask, EVL,
MMO->getPointerInfo(), MMO->getAlign(), MMO->getFlags(),
MMO->getAAInfo());
ReplaceValueWith(SDValue(N, 1), NewLoad.getValue(1));
return NewLoad;
}
report_fatal_error("Unable to widen vector load");
}
SDValue DAGTypeLegalizer::WidenVecRes_VP_LOAD(VPLoadSDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue Mask = N->getMask();
SDValue EVL = N->getVectorLength();
ISD::LoadExtType ExtType = N->getExtensionType();
SDLoc dl(N);
assert(getTypeAction(Mask.getValueType()) ==
TargetLowering::TypeWidenVector &&
"Unable to widen binary VP op");
Mask = GetWidenedVector(Mask);
assert(Mask.getValueType().getVectorElementCount() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Mask.getValueType())
.getVectorElementCount() &&
"Unable to widen vector load");
SDValue Res =
DAG.getLoadVP(N->getAddressingMode(), ExtType, WidenVT, dl, N->getChain(),
N->getBasePtr(), N->getOffset(), Mask, EVL,
N->getMemoryVT(), N->getMemOperand(), N->isExpandingLoad());
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
return Res;
}
SDValue DAGTypeLegalizer::WidenVecRes_MLOAD(MaskedLoadSDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(),N->getValueType(0));
SDValue Mask = N->getMask();
EVT MaskVT = Mask.getValueType();
SDValue PassThru = GetWidenedVector(N->getPassThru());
ISD::LoadExtType ExtType = N->getExtensionType();
SDLoc dl(N);
EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(),
MaskVT.getVectorElementType(),
WidenVT.getVectorNumElements());
Mask = ModifyToType(Mask, WideMaskVT, true);
SDValue Res = DAG.getMaskedLoad(
WidenVT, dl, N->getChain(), N->getBasePtr(), N->getOffset(), Mask,
PassThru, N->getMemoryVT(), N->getMemOperand(), N->getAddressingMode(),
ExtType, N->isExpandingLoad());
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
return Res;
}
SDValue DAGTypeLegalizer::WidenVecRes_MGATHER(MaskedGatherSDNode *N) {
EVT WideVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue Mask = N->getMask();
EVT MaskVT = Mask.getValueType();
SDValue PassThru = GetWidenedVector(N->getPassThru());
SDValue Scale = N->getScale();
unsigned NumElts = WideVT.getVectorNumElements();
SDLoc dl(N);
EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(),
MaskVT.getVectorElementType(),
WideVT.getVectorNumElements());
Mask = ModifyToType(Mask, WideMaskVT, true);
SDValue Index = N->getIndex();
EVT WideIndexVT = EVT::getVectorVT(*DAG.getContext(),
Index.getValueType().getScalarType(),
NumElts);
Index = ModifyToType(Index, WideIndexVT);
SDValue Ops[] = { N->getChain(), PassThru, Mask, N->getBasePtr(), Index,
Scale };
EVT WideMemVT = EVT::getVectorVT(*DAG.getContext(),
N->getMemoryVT().getScalarType(), NumElts);
SDValue Res = DAG.getMaskedGather(DAG.getVTList(WideVT, MVT::Other),
WideMemVT, dl, Ops, N->getMemOperand(),
N->getIndexType(), N->getExtensionType());
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
return Res;
}
SDValue DAGTypeLegalizer::WidenVecRes_VP_GATHER(VPGatherSDNode *N) {
EVT WideVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
SDValue Mask = N->getMask();
SDValue Scale = N->getScale();
ElementCount WideEC = WideVT.getVectorElementCount();
SDLoc dl(N);
SDValue Index = GetWidenedVector(N->getIndex());
EVT WideMemVT = EVT::getVectorVT(*DAG.getContext(),
N->getMemoryVT().getScalarType(), WideEC);
Mask = GetWidenedMask(Mask, WideEC);
SDValue Ops[] = {N->getChain(), N->getBasePtr(), Index, Scale,
Mask, N->getVectorLength()};
SDValue Res = DAG.getGatherVP(DAG.getVTList(WideVT, MVT::Other), WideMemVT,
dl, Ops, N->getMemOperand(), N->getIndexType());
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
return Res;
}
SDValue DAGTypeLegalizer::WidenVecRes_ScalarOp(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, N->getOperand(0));
}
static inline bool isSETCCOp(unsigned Opcode) {
switch (Opcode) {
case ISD::SETCC:
case ISD::STRICT_FSETCC:
case ISD::STRICT_FSETCCS:
return true;
}
return false;
}
static inline bool isLogicalMaskOp(unsigned Opcode) {
switch (Opcode) {
case ISD::AND:
case ISD::OR:
case ISD::XOR:
return true;
}
return false;
}
static inline EVT getSETCCOperandType(SDValue N) {
unsigned OpNo = N->isStrictFPOpcode() ? 1 : 0;
return N->getOperand(OpNo).getValueType();
}
#ifndef NDEBUG
static inline bool isSETCCorConvertedSETCC(SDValue N) {
if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR)
N = N.getOperand(0);
else if (N.getOpcode() == ISD::CONCAT_VECTORS) {
for (unsigned i = 1; i < N->getNumOperands(); ++i)
if (!N->getOperand(i)->isUndef())
return false;
N = N.getOperand(0);
}
if (N.getOpcode() == ISD::TRUNCATE)
N = N.getOperand(0);
else if (N.getOpcode() == ISD::SIGN_EXTEND)
N = N.getOperand(0);
if (isLogicalMaskOp(N.getOpcode()))
return isSETCCorConvertedSETCC(N.getOperand(0)) &&
isSETCCorConvertedSETCC(N.getOperand(1));
return (isSETCCOp(N.getOpcode()) ||
ISD::isBuildVectorOfConstantSDNodes(N.getNode()));
}
#endif
SDValue DAGTypeLegalizer::convertMask(SDValue InMask, EVT MaskVT,
EVT ToMaskVT) {
assert(isSETCCorConvertedSETCC(InMask) && "Unexpected mask argument.");
SDValue Mask;
SmallVector<SDValue, 4> Ops;
for (unsigned i = 0, e = InMask->getNumOperands(); i < e; ++i)
Ops.push_back(InMask->getOperand(i));
if (InMask->isStrictFPOpcode()) {
Mask = DAG.getNode(InMask->getOpcode(), SDLoc(InMask),
{ MaskVT, MVT::Other }, Ops);
ReplaceValueWith(InMask.getValue(1), Mask.getValue(1));
}
else
Mask = DAG.getNode(InMask->getOpcode(), SDLoc(InMask), MaskVT, Ops);
LLVMContext &Ctx = *DAG.getContext();
unsigned MaskScalarBits = MaskVT.getScalarSizeInBits();
unsigned ToMaskScalBits = ToMaskVT.getScalarSizeInBits();
if (MaskScalarBits < ToMaskScalBits) {
EVT ExtVT = EVT::getVectorVT(Ctx, ToMaskVT.getVectorElementType(),
MaskVT.getVectorNumElements());
Mask = DAG.getNode(ISD::SIGN_EXTEND, SDLoc(Mask), ExtVT, Mask);
} else if (MaskScalarBits > ToMaskScalBits) {
EVT TruncVT = EVT::getVectorVT(Ctx, ToMaskVT.getVectorElementType(),
MaskVT.getVectorNumElements());
Mask = DAG.getNode(ISD::TRUNCATE, SDLoc(Mask), TruncVT, Mask);
}
assert(Mask->getValueType(0).getScalarSizeInBits() ==
ToMaskVT.getScalarSizeInBits() &&
"Mask should have the right element size by now.");
unsigned CurrMaskNumEls = Mask->getValueType(0).getVectorNumElements();
if (CurrMaskNumEls > ToMaskVT.getVectorNumElements()) {
SDValue ZeroIdx = DAG.getVectorIdxConstant(0, SDLoc(Mask));
Mask = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(Mask), ToMaskVT, Mask,
ZeroIdx);
} else if (CurrMaskNumEls < ToMaskVT.getVectorNumElements()) {
unsigned NumSubVecs = (ToMaskVT.getVectorNumElements() / CurrMaskNumEls);
EVT SubVT = Mask->getValueType(0);
SmallVector<SDValue, 16> SubOps(NumSubVecs, DAG.getUNDEF(SubVT));
SubOps[0] = Mask;
Mask = DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(Mask), ToMaskVT, SubOps);
}
assert((Mask->getValueType(0) == ToMaskVT) &&
"A mask of ToMaskVT should have been produced by now.");
return Mask;
}
SDValue DAGTypeLegalizer::WidenVSELECTMask(SDNode *N) {
LLVMContext &Ctx = *DAG.getContext();
SDValue Cond = N->getOperand(0);
if (N->getOpcode() != ISD::VSELECT)
return SDValue();
if (!isSETCCOp(Cond->getOpcode()) && !isLogicalMaskOp(Cond->getOpcode()))
return SDValue();
EVT CondVT = Cond->getValueType(0);
if (CondVT.getScalarSizeInBits() != 1)
return SDValue();
EVT VSelVT = N->getValueType(0);
if (VSelVT.isScalableVector())
return SDValue();
if (!isPowerOf2_64(VSelVT.getSizeInBits()))
return SDValue();
EVT FinalVT = VSelVT;
while (getTypeAction(FinalVT) == TargetLowering::TypeSplitVector)
FinalVT = FinalVT.getHalfNumVectorElementsVT(Ctx);
if (FinalVT.getVectorNumElements() == 1)
return SDValue();
if (isSETCCOp(Cond.getOpcode())) {
EVT SetCCOpVT = getSETCCOperandType(Cond);
while (TLI.getTypeAction(Ctx, SetCCOpVT) != TargetLowering::TypeLegal)
SetCCOpVT = TLI.getTypeToTransformTo(Ctx, SetCCOpVT);
EVT SetCCResVT = getSetCCResultType(SetCCOpVT);
if (SetCCResVT.getScalarSizeInBits() == 1)
return SDValue();
} else if (CondVT.getScalarType() == MVT::i1) {
while (TLI.getTypeAction(Ctx, CondVT) != TargetLowering::TypeLegal)
CondVT = TLI.getTypeToTransformTo(Ctx, CondVT);
if (CondVT.getScalarType() == MVT::i1)
return SDValue();
}
if (getTypeAction(VSelVT) == TargetLowering::TypeWidenVector)
VSelVT = TLI.getTypeToTransformTo(Ctx, VSelVT);
EVT ToMaskVT = VSelVT;
if (!ToMaskVT.getScalarType().isInteger())
ToMaskVT = ToMaskVT.changeVectorElementTypeToInteger();
SDValue Mask;
if (isSETCCOp(Cond->getOpcode())) {
EVT MaskVT = getSetCCResultType(getSETCCOperandType(Cond));
Mask = convertMask(Cond, MaskVT, ToMaskVT);
} else if (isLogicalMaskOp(Cond->getOpcode()) &&
isSETCCOp(Cond->getOperand(0).getOpcode()) &&
isSETCCOp(Cond->getOperand(1).getOpcode())) {
SDValue SETCC0 = Cond->getOperand(0);
SDValue SETCC1 = Cond->getOperand(1);
EVT VT0 = getSetCCResultType(getSETCCOperandType(SETCC0));
EVT VT1 = getSetCCResultType(getSETCCOperandType(SETCC1));
unsigned ScalarBits0 = VT0.getScalarSizeInBits();
unsigned ScalarBits1 = VT1.getScalarSizeInBits();
unsigned ScalarBits_ToMask = ToMaskVT.getScalarSizeInBits();
EVT MaskVT;
if (ScalarBits0 != ScalarBits1) {
EVT NarrowVT = ((ScalarBits0 < ScalarBits1) ? VT0 : VT1);
EVT WideVT = ((NarrowVT == VT0) ? VT1 : VT0);
if (ScalarBits_ToMask >= WideVT.getScalarSizeInBits())
MaskVT = WideVT;
else if (ScalarBits_ToMask <= NarrowVT.getScalarSizeInBits())
MaskVT = NarrowVT;
else
MaskVT = ToMaskVT;
} else
MaskVT = VT0;
SETCC0 = convertMask(SETCC0, VT0, MaskVT);
SETCC1 = convertMask(SETCC1, VT1, MaskVT);
Cond = DAG.getNode(Cond->getOpcode(), SDLoc(Cond), MaskVT, SETCC0, SETCC1);
Mask = convertMask(Cond, MaskVT, ToMaskVT);
} else
return SDValue();
return Mask;
}
SDValue DAGTypeLegalizer::WidenVecRes_Select(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
ElementCount WidenEC = WidenVT.getVectorElementCount();
SDValue Cond1 = N->getOperand(0);
EVT CondVT = Cond1.getValueType();
unsigned Opcode = N->getOpcode();
if (CondVT.isVector()) {
if (SDValue WideCond = WidenVSELECTMask(N)) {
SDValue InOp1 = GetWidenedVector(N->getOperand(1));
SDValue InOp2 = GetWidenedVector(N->getOperand(2));
assert(InOp1.getValueType() == WidenVT && InOp2.getValueType() == WidenVT);
return DAG.getNode(Opcode, SDLoc(N), WidenVT, WideCond, InOp1, InOp2);
}
EVT CondEltVT = CondVT.getVectorElementType();
EVT CondWidenVT = EVT::getVectorVT(*DAG.getContext(), CondEltVT, WidenEC);
if (getTypeAction(CondVT) == TargetLowering::TypeWidenVector)
Cond1 = GetWidenedVector(Cond1);
if (getTypeAction(CondVT) == TargetLowering::TypeSplitVector) {
SDValue SplitSelect = SplitVecOp_VSELECT(N, 0);
SDValue Res = ModifyToType(SplitSelect, WidenVT);
return Res;
}
if (Cond1.getValueType() != CondWidenVT)
Cond1 = ModifyToType(Cond1, CondWidenVT);
}
SDValue InOp1 = GetWidenedVector(N->getOperand(1));
SDValue InOp2 = GetWidenedVector(N->getOperand(2));
assert(InOp1.getValueType() == WidenVT && InOp2.getValueType() == WidenVT);
if (Opcode == ISD::VP_SELECT || Opcode == ISD::VP_MERGE)
return DAG.getNode(Opcode, SDLoc(N), WidenVT, Cond1, InOp1, InOp2,
N->getOperand(3));
return DAG.getNode(Opcode, SDLoc(N), WidenVT, Cond1, InOp1, InOp2);
}
SDValue DAGTypeLegalizer::WidenVecRes_SELECT_CC(SDNode *N) {
SDValue InOp1 = GetWidenedVector(N->getOperand(2));
SDValue InOp2 = GetWidenedVector(N->getOperand(3));
return DAG.getNode(ISD::SELECT_CC, SDLoc(N),
InOp1.getValueType(), N->getOperand(0),
N->getOperand(1), InOp1, InOp2, N->getOperand(4));
}
SDValue DAGTypeLegalizer::WidenVecRes_UNDEF(SDNode *N) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
return DAG.getUNDEF(WidenVT);
}
SDValue DAGTypeLegalizer::WidenVecRes_VECTOR_SHUFFLE(ShuffleVectorSDNode *N) {
EVT VT = N->getValueType(0);
SDLoc dl(N);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
unsigned NumElts = VT.getVectorNumElements();
unsigned WidenNumElts = WidenVT.getVectorNumElements();
SDValue InOp1 = GetWidenedVector(N->getOperand(0));
SDValue InOp2 = GetWidenedVector(N->getOperand(1));
SmallVector<int, 16> NewMask;
for (unsigned i = 0; i != NumElts; ++i) {
int Idx = N->getMaskElt(i);
if (Idx < (int)NumElts)
NewMask.push_back(Idx);
else
NewMask.push_back(Idx - NumElts + WidenNumElts);
}
for (unsigned i = NumElts; i != WidenNumElts; ++i)
NewMask.push_back(-1);
return DAG.getVectorShuffle(WidenVT, dl, InOp1, InOp2, NewMask);
}
SDValue DAGTypeLegalizer::WidenVecRes_SETCC(SDNode *N) {
assert(N->getValueType(0).isVector() &&
N->getOperand(0).getValueType().isVector() &&
"Operands must be vectors");
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
ElementCount WidenEC = WidenVT.getVectorElementCount();
SDValue InOp1 = N->getOperand(0);
EVT InVT = InOp1.getValueType();
assert(InVT.isVector() && "can not widen non-vector type");
EVT WidenInVT =
EVT::getVectorVT(*DAG.getContext(), InVT.getVectorElementType(), WidenEC);
if (getTypeAction(InVT) == TargetLowering::TypeSplitVector) {
SDValue SplitVSetCC = SplitVecOp_VSETCC(N);
SDValue Res = ModifyToType(SplitVSetCC, WidenVT);
return Res;
}
SDValue InOp2 = N->getOperand(1);
if (getTypeAction(InVT) == TargetLowering::TypeWidenVector) {
InOp1 = GetWidenedVector(InOp1);
InOp2 = GetWidenedVector(InOp2);
} else {
InOp1 = DAG.WidenVector(InOp1, SDLoc(N));
InOp2 = DAG.WidenVector(InOp2, SDLoc(N));
}
assert(InOp1.getValueType() == WidenInVT &&
InOp2.getValueType() == WidenInVT &&
"Input not widened to expected type!");
(void)WidenInVT;
if (N->getOpcode() == ISD::VP_SETCC) {
SDValue Mask =
GetWidenedMask(N->getOperand(3), WidenVT.getVectorElementCount());
return DAG.getNode(ISD::VP_SETCC, SDLoc(N), WidenVT, InOp1, InOp2,
N->getOperand(2), Mask, N->getOperand(4));
}
return DAG.getNode(ISD::SETCC, SDLoc(N), WidenVT, InOp1, InOp2,
N->getOperand(2));
}
SDValue DAGTypeLegalizer::WidenVecRes_STRICT_FSETCC(SDNode *N) {
assert(N->getValueType(0).isVector() &&
N->getOperand(1).getValueType().isVector() &&
"Operands must be vectors");
EVT VT = N->getValueType(0);
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
unsigned WidenNumElts = WidenVT.getVectorNumElements();
unsigned NumElts = VT.getVectorNumElements();
EVT EltVT = VT.getVectorElementType();
SDLoc dl(N);
SDValue Chain = N->getOperand(0);
SDValue LHS = N->getOperand(1);
SDValue RHS = N->getOperand(2);
SDValue CC = N->getOperand(3);
EVT TmpEltVT = LHS.getValueType().getVectorElementType();
SmallVector<SDValue, 8> Scalars(WidenNumElts, DAG.getUNDEF(EltVT));
SmallVector<SDValue, 8> Chains(NumElts);
for (unsigned i = 0; i != NumElts; ++i) {
SDValue LHSElem = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, TmpEltVT, LHS,
DAG.getVectorIdxConstant(i, dl));
SDValue RHSElem = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, TmpEltVT, RHS,
DAG.getVectorIdxConstant(i, dl));
Scalars[i] = DAG.getNode(N->getOpcode(), dl, {MVT::i1, MVT::Other},
{Chain, LHSElem, RHSElem, CC});
Chains[i] = Scalars[i].getValue(1);
Scalars[i] = DAG.getSelect(dl, EltVT, Scalars[i],
DAG.getBoolConstant(true, dl, EltVT, VT),
DAG.getBoolConstant(false, dl, EltVT, VT));
}
SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Chains);
ReplaceValueWith(SDValue(N, 1), NewChain);
return DAG.getBuildVector(WidenVT, dl, Scalars);
}
bool DAGTypeLegalizer::WidenVectorOperand(SDNode *N, unsigned OpNo) {
LLVM_DEBUG(dbgs() << "Widen node operand " << OpNo << ": "; N->dump(&DAG);
dbgs() << "\n");
SDValue Res = SDValue();
if (CustomLowerNode(N, N->getOperand(OpNo).getValueType(), false))
return false;
switch (N->getOpcode()) {
default:
#ifndef NDEBUG
dbgs() << "WidenVectorOperand op #" << OpNo << ": ";
N->dump(&DAG);
dbgs() << "\n";
#endif
llvm_unreachable("Do not know how to widen this operator's operand!");
case ISD::BITCAST: Res = WidenVecOp_BITCAST(N); break;
case ISD::CONCAT_VECTORS: Res = WidenVecOp_CONCAT_VECTORS(N); break;
case ISD::INSERT_SUBVECTOR: Res = WidenVecOp_INSERT_SUBVECTOR(N); break;
case ISD::EXTRACT_SUBVECTOR: Res = WidenVecOp_EXTRACT_SUBVECTOR(N); break;
case ISD::EXTRACT_VECTOR_ELT: Res = WidenVecOp_EXTRACT_VECTOR_ELT(N); break;
case ISD::STORE: Res = WidenVecOp_STORE(N); break;
case ISD::VP_STORE: Res = WidenVecOp_VP_STORE(N, OpNo); break;
case ISD::MSTORE: Res = WidenVecOp_MSTORE(N, OpNo); break;
case ISD::MGATHER: Res = WidenVecOp_MGATHER(N, OpNo); break;
case ISD::MSCATTER: Res = WidenVecOp_MSCATTER(N, OpNo); break;
case ISD::VP_SCATTER: Res = WidenVecOp_VP_SCATTER(N, OpNo); break;
case ISD::SETCC: Res = WidenVecOp_SETCC(N); break;
case ISD::STRICT_FSETCC:
case ISD::STRICT_FSETCCS: Res = WidenVecOp_STRICT_FSETCC(N); break;
case ISD::VSELECT: Res = WidenVecOp_VSELECT(N); break;
case ISD::FCOPYSIGN: Res = WidenVecOp_FCOPYSIGN(N); break;
case ISD::IS_FPCLASS: Res = WidenVecOp_IS_FPCLASS(N); break;
case ISD::ANY_EXTEND:
case ISD::SIGN_EXTEND:
case ISD::ZERO_EXTEND:
Res = WidenVecOp_EXTEND(N);
break;
case ISD::FP_EXTEND:
case ISD::STRICT_FP_EXTEND:
case ISD::FP_ROUND:
case ISD::STRICT_FP_ROUND:
case ISD::FP_TO_SINT:
case ISD::STRICT_FP_TO_SINT:
case ISD::FP_TO_UINT:
case ISD::STRICT_FP_TO_UINT:
case ISD::SINT_TO_FP:
case ISD::STRICT_SINT_TO_FP:
case ISD::UINT_TO_FP:
case ISD::STRICT_UINT_TO_FP:
case ISD::TRUNCATE:
Res = WidenVecOp_Convert(N);
break;
case ISD::FP_TO_SINT_SAT:
case ISD::FP_TO_UINT_SAT:
Res = WidenVecOp_FP_TO_XINT_SAT(N);
break;
case ISD::VECREDUCE_FADD:
case ISD::VECREDUCE_FMUL:
case ISD::VECREDUCE_ADD:
case ISD::VECREDUCE_MUL:
case ISD::VECREDUCE_AND:
case ISD::VECREDUCE_OR:
case ISD::VECREDUCE_XOR:
case ISD::VECREDUCE_SMAX:
case ISD::VECREDUCE_SMIN:
case ISD::VECREDUCE_UMAX:
case ISD::VECREDUCE_UMIN:
case ISD::VECREDUCE_FMAX:
case ISD::VECREDUCE_FMIN:
Res = WidenVecOp_VECREDUCE(N);
break;
case ISD::VECREDUCE_SEQ_FADD:
case ISD::VECREDUCE_SEQ_FMUL:
Res = WidenVecOp_VECREDUCE_SEQ(N);
break;
case ISD::VP_REDUCE_FADD:
case ISD::VP_REDUCE_SEQ_FADD:
case ISD::VP_REDUCE_FMUL:
case ISD::VP_REDUCE_SEQ_FMUL:
case ISD::VP_REDUCE_ADD:
case ISD::VP_REDUCE_MUL:
case ISD::VP_REDUCE_AND:
case ISD::VP_REDUCE_OR:
case ISD::VP_REDUCE_XOR:
case ISD::VP_REDUCE_SMAX:
case ISD::VP_REDUCE_SMIN:
case ISD::VP_REDUCE_UMAX:
case ISD::VP_REDUCE_UMIN:
case ISD::VP_REDUCE_FMAX:
case ISD::VP_REDUCE_FMIN:
Res = WidenVecOp_VP_REDUCE(N);
break;
}
if (!Res.getNode()) return false;
if (Res.getNode() == N)
return true;
if (N->isStrictFPOpcode())
assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == 2 &&
"Invalid operand expansion");
else
assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == 1 &&
"Invalid operand expansion");
ReplaceValueWith(SDValue(N, 0), Res);
return false;
}
SDValue DAGTypeLegalizer::WidenVecOp_EXTEND(SDNode *N) {
SDLoc DL(N);
EVT VT = N->getValueType(0);
SDValue InOp = N->getOperand(0);
assert(getTypeAction(InOp.getValueType()) ==
TargetLowering::TypeWidenVector &&
"Unexpected type action");
InOp = GetWidenedVector(InOp);
assert(VT.getVectorNumElements() <
InOp.getValueType().getVectorNumElements() &&
"Input wasn't widened!");
EVT InVT = InOp.getValueType();
if (InVT.getSizeInBits() != VT.getSizeInBits()) {
EVT InEltVT = InVT.getVectorElementType();
for (EVT FixedVT : MVT::vector_valuetypes()) {
EVT FixedEltVT = FixedVT.getVectorElementType();
if (TLI.isTypeLegal(FixedVT) &&
FixedVT.getSizeInBits() == VT.getSizeInBits() &&
FixedEltVT == InEltVT) {
assert(FixedVT.getVectorNumElements() >= VT.getVectorNumElements() &&
"Not enough elements in the fixed type for the operand!");
assert(FixedVT.getVectorNumElements() != InVT.getVectorNumElements() &&
"We can't have the same type as we started with!");
if (FixedVT.getVectorNumElements() > InVT.getVectorNumElements())
InOp = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, FixedVT,
DAG.getUNDEF(FixedVT), InOp,
DAG.getVectorIdxConstant(0, DL));
else
InOp = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, FixedVT, InOp,
DAG.getVectorIdxConstant(0, DL));
break;
}
}
InVT = InOp.getValueType();
if (InVT.getSizeInBits() != VT.getSizeInBits())
return WidenVecOp_Convert(N);
}
switch (N->getOpcode()) {
default:
llvm_unreachable("Extend legalization on extend operation!");
case ISD::ANY_EXTEND:
return DAG.getNode(ISD::ANY_EXTEND_VECTOR_INREG, DL, VT, InOp);
case ISD::SIGN_EXTEND:
return DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, VT, InOp);
case ISD::ZERO_EXTEND:
return DAG.getNode(ISD::ZERO_EXTEND_VECTOR_INREG, DL, VT, InOp);
}
}
SDValue DAGTypeLegalizer::WidenVecOp_FCOPYSIGN(SDNode *N) {
return DAG.UnrollVectorOp(N);
}
SDValue DAGTypeLegalizer::WidenVecOp_IS_FPCLASS(SDNode *N) {
SDLoc DL(N);
EVT ResultVT = N->getValueType(0);
SDValue Test = N->getOperand(1);
SDValue WideArg = GetWidenedVector(N->getOperand(0));
EVT WideResultVT = getSetCCResultType(WideArg.getValueType());
if (ResultVT.getScalarType() == MVT::i1)
WideResultVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
WideResultVT.getVectorNumElements());
SDValue WideNode = DAG.getNode(ISD::IS_FPCLASS, DL, WideResultVT,
{WideArg, Test}, N->getFlags());
EVT ResVT =
EVT::getVectorVT(*DAG.getContext(), WideResultVT.getVectorElementType(),
ResultVT.getVectorNumElements());
SDValue CC = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResVT, WideNode,
DAG.getVectorIdxConstant(0, DL));
EVT OpVT = N->getOperand(0).getValueType();
ISD::NodeType ExtendCode =
TargetLowering::getExtendForContent(TLI.getBooleanContents(OpVT));
return DAG.getNode(ExtendCode, DL, ResultVT, CC);
}
SDValue DAGTypeLegalizer::WidenVecOp_Convert(SDNode *N) {
EVT VT = N->getValueType(0);
EVT EltVT = VT.getVectorElementType();
SDLoc dl(N);
SDValue InOp = N->getOperand(N->isStrictFPOpcode() ? 1 : 0);
assert(getTypeAction(InOp.getValueType()) ==
TargetLowering::TypeWidenVector &&
"Unexpected type action");
InOp = GetWidenedVector(InOp);
EVT InVT = InOp.getValueType();
unsigned Opcode = N->getOpcode();
EVT WideVT = EVT::getVectorVT(*DAG.getContext(), EltVT,
InVT.getVectorElementCount());
if (TLI.isTypeLegal(WideVT) && !N->isStrictFPOpcode()) {
SDValue Res;
if (N->isStrictFPOpcode()) {
if (Opcode == ISD::STRICT_FP_ROUND)
Res = DAG.getNode(Opcode, dl, { WideVT, MVT::Other },
{ N->getOperand(0), InOp, N->getOperand(2) });
else
Res = DAG.getNode(Opcode, dl, { WideVT, MVT::Other },
{ N->getOperand(0), InOp });
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
} else {
if (Opcode == ISD::FP_ROUND)
Res = DAG.getNode(Opcode, dl, WideVT, InOp, N->getOperand(1));
else
Res = DAG.getNode(Opcode, dl, WideVT, InOp);
}
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, Res,
DAG.getVectorIdxConstant(0, dl));
}
EVT InEltVT = InVT.getVectorElementType();
unsigned NumElts = VT.getVectorNumElements();
SmallVector<SDValue, 16> Ops(NumElts);
if (N->isStrictFPOpcode()) {
SmallVector<SDValue, 4> NewOps(N->op_begin(), N->op_end());
SmallVector<SDValue, 32> OpChains;
for (unsigned i=0; i < NumElts; ++i) {
NewOps[1] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, InEltVT, InOp,
DAG.getVectorIdxConstant(i, dl));
Ops[i] = DAG.getNode(Opcode, dl, { EltVT, MVT::Other }, NewOps);
OpChains.push_back(Ops[i].getValue(1));
}
SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OpChains);
ReplaceValueWith(SDValue(N, 1), NewChain);
} else {
for (unsigned i = 0; i < NumElts; ++i)
Ops[i] = DAG.getNode(Opcode, dl, EltVT,
DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, InEltVT,
InOp, DAG.getVectorIdxConstant(i, dl)));
}
return DAG.getBuildVector(VT, dl, Ops);
}
SDValue DAGTypeLegalizer::WidenVecOp_FP_TO_XINT_SAT(SDNode *N) {
EVT DstVT = N->getValueType(0);
SDValue Src = GetWidenedVector(N->getOperand(0));
EVT SrcVT = Src.getValueType();
ElementCount WideNumElts = SrcVT.getVectorElementCount();
SDLoc dl(N);
EVT WideDstVT = EVT::getVectorVT(*DAG.getContext(),
DstVT.getVectorElementType(), WideNumElts);
if (TLI.isTypeLegal(WideDstVT)) {
SDValue Res =
DAG.getNode(N->getOpcode(), dl, WideDstVT, Src, N->getOperand(1));
return DAG.getNode(
ISD::EXTRACT_SUBVECTOR, dl, DstVT, Res,
DAG.getConstant(0, dl, TLI.getVectorIdxTy(DAG.getDataLayout())));
}
return DAG.UnrollVectorOp(N);
}
SDValue DAGTypeLegalizer::WidenVecOp_BITCAST(SDNode *N) {
EVT VT = N->getValueType(0);
SDValue InOp = GetWidenedVector(N->getOperand(0));
EVT InWidenVT = InOp.getValueType();
SDLoc dl(N);
TypeSize InWidenSize = InWidenVT.getSizeInBits();
TypeSize Size = VT.getSizeInBits();
if (!VT.isVector() && VT != MVT::x86mmx &&
InWidenSize.hasKnownScalarFactor(Size)) {
unsigned NewNumElts = InWidenSize.getKnownScalarFactor(Size);
EVT NewVT = EVT::getVectorVT(*DAG.getContext(), VT, NewNumElts);
if (TLI.isTypeLegal(NewVT)) {
SDValue BitOp = DAG.getNode(ISD::BITCAST, dl, NewVT, InOp);
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, VT, BitOp,
DAG.getVectorIdxConstant(0, dl));
}
}
if (VT.isVector()) {
EVT EltVT = VT.getVectorElementType();
unsigned EltSize = EltVT.getFixedSizeInBits();
if (InWidenSize.isKnownMultipleOf(EltSize)) {
ElementCount NewNumElts =
(InWidenVT.getVectorElementCount() * InWidenVT.getScalarSizeInBits())
.divideCoefficientBy(EltSize);
EVT NewVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NewNumElts);
if (TLI.isTypeLegal(NewVT)) {
SDValue BitOp = DAG.getNode(ISD::BITCAST, dl, NewVT, InOp);
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, BitOp,
DAG.getVectorIdxConstant(0, dl));
}
}
}
return CreateStackStoreLoad(InOp, VT);
}
SDValue DAGTypeLegalizer::WidenVecOp_CONCAT_VECTORS(SDNode *N) {
EVT VT = N->getValueType(0);
EVT EltVT = VT.getVectorElementType();
EVT InVT = N->getOperand(0).getValueType();
SDLoc dl(N);
unsigned NumOperands = N->getNumOperands();
if (VT == TLI.getTypeToTransformTo(*DAG.getContext(), InVT)) {
unsigned i;
for (i = 1; i < NumOperands; ++i)
if (!N->getOperand(i).isUndef())
break;
if (i == NumOperands)
return GetWidenedVector(N->getOperand(0));
}
unsigned NumElts = VT.getVectorNumElements();
SmallVector<SDValue, 16> Ops(NumElts);
unsigned NumInElts = InVT.getVectorNumElements();
unsigned Idx = 0;
for (unsigned i=0; i < NumOperands; ++i) {
SDValue InOp = N->getOperand(i);
assert(getTypeAction(InOp.getValueType()) ==
TargetLowering::TypeWidenVector &&
"Unexpected type action");
InOp = GetWidenedVector(InOp);
for (unsigned j = 0; j < NumInElts; ++j)
Ops[Idx++] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp,
DAG.getVectorIdxConstant(j, dl));
}
return DAG.getBuildVector(VT, dl, Ops);
}
SDValue DAGTypeLegalizer::WidenVecOp_INSERT_SUBVECTOR(SDNode *N) {
EVT VT = N->getValueType(0);
SDValue SubVec = N->getOperand(1);
SDValue InVec = N->getOperand(0);
if (getTypeAction(SubVec.getValueType()) == TargetLowering::TypeWidenVector)
SubVec = GetWidenedVector(SubVec);
if (SubVec.getValueType().knownBitsLE(VT) && InVec.isUndef() &&
N->getConstantOperandVal(2) == 0)
return DAG.getNode(ISD::INSERT_SUBVECTOR, SDLoc(N), VT, InVec, SubVec,
N->getOperand(2));
report_fatal_error("Don't know how to widen the operands for "
"INSERT_SUBVECTOR");
}
SDValue DAGTypeLegalizer::WidenVecOp_EXTRACT_SUBVECTOR(SDNode *N) {
SDValue InOp = GetWidenedVector(N->getOperand(0));
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(N),
N->getValueType(0), InOp, N->getOperand(1));
}
SDValue DAGTypeLegalizer::WidenVecOp_EXTRACT_VECTOR_ELT(SDNode *N) {
SDValue InOp = GetWidenedVector(N->getOperand(0));
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(N),
N->getValueType(0), InOp, N->getOperand(1));
}
SDValue DAGTypeLegalizer::WidenVecOp_STORE(SDNode *N) {
StoreSDNode *ST = cast<StoreSDNode>(N);
if (!ST->getMemoryVT().getScalarType().isByteSized())
return TLI.scalarizeVectorStore(ST, DAG);
if (ST->isTruncatingStore())
return TLI.scalarizeVectorStore(ST, DAG);
SmallVector<SDValue, 16> StChain;
if (GenWidenVectorStores(StChain, ST)) {
if (StChain.size() == 1)
return StChain[0];
return DAG.getNode(ISD::TokenFactor, SDLoc(ST), MVT::Other, StChain);
}
SDValue StVal = ST->getValue();
EVT StVT = StVal.getValueType();
EVT WideVT = TLI.getTypeToTransformTo(*DAG.getContext(), StVT);
EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
WideVT.getVectorElementCount());
if (WideVT.isScalableVector() &&
TLI.isOperationLegalOrCustom(ISD::VP_STORE, WideVT) &&
TLI.isTypeLegal(WideMaskVT)) {
SDLoc DL(N);
StVal = GetWidenedVector(StVal);
SDValue Mask = DAG.getAllOnesConstant(DL, WideMaskVT);
MVT EVLVT = TLI.getVPExplicitVectorLengthTy();
unsigned NumVTElts = StVT.getVectorMinNumElements();
SDValue EVL =
DAG.getVScale(DL, EVLVT, APInt(EVLVT.getScalarSizeInBits(), NumVTElts));
return DAG.getStoreVP(ST->getChain(), DL, StVal, ST->getBasePtr(),
DAG.getUNDEF(ST->getBasePtr().getValueType()), Mask,
EVL, StVal.getValueType(), ST->getMemOperand(),
ST->getAddressingMode());
}
report_fatal_error("Unable to widen vector store");
}
SDValue DAGTypeLegalizer::WidenVecOp_VP_STORE(SDNode *N, unsigned OpNo) {
assert((OpNo == 1 || OpNo == 3) &&
"Can widen only data or mask operand of vp_store");
VPStoreSDNode *ST = cast<VPStoreSDNode>(N);
SDValue Mask = ST->getMask();
SDValue StVal = ST->getValue();
SDLoc dl(N);
if (OpNo == 1) {
StVal = GetWidenedVector(StVal);
assert(getTypeAction(Mask.getValueType()) ==
TargetLowering::TypeWidenVector &&
"Unable to widen VP store");
Mask = GetWidenedVector(Mask);
} else {
Mask = GetWidenedVector(Mask);
assert(getTypeAction(StVal.getValueType()) ==
TargetLowering::TypeWidenVector &&
"Unable to widen VP store");
StVal = GetWidenedVector(StVal);
}
assert(Mask.getValueType().getVectorElementCount() ==
StVal.getValueType().getVectorElementCount() &&
"Mask and data vectors should have the same number of elements");
return DAG.getStoreVP(ST->getChain(), dl, StVal, ST->getBasePtr(),
ST->getOffset(), Mask, ST->getVectorLength(),
ST->getMemoryVT(), ST->getMemOperand(),
ST->getAddressingMode(), ST->isTruncatingStore(),
ST->isCompressingStore());
}
SDValue DAGTypeLegalizer::WidenVecOp_MSTORE(SDNode *N, unsigned OpNo) {
assert((OpNo == 1 || OpNo == 3) &&
"Can widen only data or mask operand of mstore");
MaskedStoreSDNode *MST = cast<MaskedStoreSDNode>(N);
SDValue Mask = MST->getMask();
EVT MaskVT = Mask.getValueType();
SDValue StVal = MST->getValue();
SDLoc dl(N);
if (OpNo == 1) {
StVal = GetWidenedVector(StVal);
EVT WideVT = StVal.getValueType();
EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(),
MaskVT.getVectorElementType(),
WideVT.getVectorNumElements());
Mask = ModifyToType(Mask, WideMaskVT, true);
} else {
EVT WideMaskVT = TLI.getTypeToTransformTo(*DAG.getContext(), MaskVT);
Mask = ModifyToType(Mask, WideMaskVT, true);
EVT ValueVT = StVal.getValueType();
EVT WideVT = EVT::getVectorVT(*DAG.getContext(),
ValueVT.getVectorElementType(),
WideMaskVT.getVectorNumElements());
StVal = ModifyToType(StVal, WideVT);
}
assert(Mask.getValueType().getVectorNumElements() ==
StVal.getValueType().getVectorNumElements() &&
"Mask and data vectors should have the same number of elements");
return DAG.getMaskedStore(MST->getChain(), dl, StVal, MST->getBasePtr(),
MST->getOffset(), Mask, MST->getMemoryVT(),
MST->getMemOperand(), MST->getAddressingMode(),
false, MST->isCompressingStore());
}
SDValue DAGTypeLegalizer::WidenVecOp_MGATHER(SDNode *N, unsigned OpNo) {
assert(OpNo == 4 && "Can widen only the index of mgather");
auto *MG = cast<MaskedGatherSDNode>(N);
SDValue DataOp = MG->getPassThru();
SDValue Mask = MG->getMask();
SDValue Scale = MG->getScale();
SDValue Index = GetWidenedVector(MG->getIndex());
SDLoc dl(N);
SDValue Ops[] = {MG->getChain(), DataOp, Mask, MG->getBasePtr(), Index,
Scale};
SDValue Res = DAG.getMaskedGather(MG->getVTList(), MG->getMemoryVT(), dl, Ops,
MG->getMemOperand(), MG->getIndexType(),
MG->getExtensionType());
ReplaceValueWith(SDValue(N, 1), Res.getValue(1));
ReplaceValueWith(SDValue(N, 0), Res.getValue(0));
return SDValue();
}
SDValue DAGTypeLegalizer::WidenVecOp_MSCATTER(SDNode *N, unsigned OpNo) {
MaskedScatterSDNode *MSC = cast<MaskedScatterSDNode>(N);
SDValue DataOp = MSC->getValue();
SDValue Mask = MSC->getMask();
SDValue Index = MSC->getIndex();
SDValue Scale = MSC->getScale();
EVT WideMemVT = MSC->getMemoryVT();
if (OpNo == 1) {
DataOp = GetWidenedVector(DataOp);
unsigned NumElts = DataOp.getValueType().getVectorNumElements();
EVT IndexVT = Index.getValueType();
EVT WideIndexVT = EVT::getVectorVT(*DAG.getContext(),
IndexVT.getVectorElementType(), NumElts);
Index = ModifyToType(Index, WideIndexVT);
EVT MaskVT = Mask.getValueType();
EVT WideMaskVT = EVT::getVectorVT(*DAG.getContext(),
MaskVT.getVectorElementType(), NumElts);
Mask = ModifyToType(Mask, WideMaskVT, true);
WideMemVT = EVT::getVectorVT(*DAG.getContext(),
MSC->getMemoryVT().getScalarType(), NumElts);
} else if (OpNo == 4) {
Index = GetWidenedVector(Index);
} else
llvm_unreachable("Can't widen this operand of mscatter");
SDValue Ops[] = {MSC->getChain(), DataOp, Mask, MSC->getBasePtr(), Index,
Scale};
return DAG.getMaskedScatter(DAG.getVTList(MVT::Other), WideMemVT, SDLoc(N),
Ops, MSC->getMemOperand(), MSC->getIndexType(),
MSC->isTruncatingStore());
}
SDValue DAGTypeLegalizer::WidenVecOp_VP_SCATTER(SDNode *N, unsigned OpNo) {
VPScatterSDNode *VPSC = cast<VPScatterSDNode>(N);
SDValue DataOp = VPSC->getValue();
SDValue Mask = VPSC->getMask();
SDValue Index = VPSC->getIndex();
SDValue Scale = VPSC->getScale();
EVT WideMemVT = VPSC->getMemoryVT();
if (OpNo == 1) {
DataOp = GetWidenedVector(DataOp);
Index = GetWidenedVector(Index);
const auto WideEC = DataOp.getValueType().getVectorElementCount();
Mask = GetWidenedMask(Mask, WideEC);
WideMemVT = EVT::getVectorVT(*DAG.getContext(),
VPSC->getMemoryVT().getScalarType(), WideEC);
} else if (OpNo == 3) {
Index = GetWidenedVector(Index);
} else
llvm_unreachable("Can't widen this operand of VP_SCATTER");
SDValue Ops[] = {
VPSC->getChain(), DataOp, VPSC->getBasePtr(), Index, Scale, Mask,
VPSC->getVectorLength()};
return DAG.getScatterVP(DAG.getVTList(MVT::Other), WideMemVT, SDLoc(N), Ops,
VPSC->getMemOperand(), VPSC->getIndexType());
}
SDValue DAGTypeLegalizer::WidenVecOp_SETCC(SDNode *N) {
SDValue InOp0 = GetWidenedVector(N->getOperand(0));
SDValue InOp1 = GetWidenedVector(N->getOperand(1));
SDLoc dl(N);
EVT VT = N->getValueType(0);
EVT SVT = getSetCCResultType(InOp0.getValueType());
if (VT.getScalarType() == MVT::i1)
SVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
SVT.getVectorElementCount());
SDValue WideSETCC = DAG.getNode(ISD::SETCC, SDLoc(N),
SVT, InOp0, InOp1, N->getOperand(2));
EVT ResVT = EVT::getVectorVT(*DAG.getContext(),
SVT.getVectorElementType(),
VT.getVectorElementCount());
SDValue CC = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, ResVT, WideSETCC,
DAG.getVectorIdxConstant(0, dl));
EVT OpVT = N->getOperand(0).getValueType();
ISD::NodeType ExtendCode =
TargetLowering::getExtendForContent(TLI.getBooleanContents(OpVT));
return DAG.getNode(ExtendCode, dl, VT, CC);
}
SDValue DAGTypeLegalizer::WidenVecOp_STRICT_FSETCC(SDNode *N) {
SDValue Chain = N->getOperand(0);
SDValue LHS = GetWidenedVector(N->getOperand(1));
SDValue RHS = GetWidenedVector(N->getOperand(2));
SDValue CC = N->getOperand(3);
SDLoc dl(N);
EVT VT = N->getValueType(0);
EVT EltVT = VT.getVectorElementType();
EVT TmpEltVT = LHS.getValueType().getVectorElementType();
unsigned NumElts = VT.getVectorNumElements();
SmallVector<SDValue, 8> Scalars(NumElts);
SmallVector<SDValue, 8> Chains(NumElts);
for (unsigned i = 0; i != NumElts; ++i) {
SDValue LHSElem = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, TmpEltVT, LHS,
DAG.getVectorIdxConstant(i, dl));
SDValue RHSElem = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, TmpEltVT, RHS,
DAG.getVectorIdxConstant(i, dl));
Scalars[i] = DAG.getNode(N->getOpcode(), dl, {MVT::i1, MVT::Other},
{Chain, LHSElem, RHSElem, CC});
Chains[i] = Scalars[i].getValue(1);
Scalars[i] = DAG.getSelect(dl, EltVT, Scalars[i],
DAG.getBoolConstant(true, dl, EltVT, VT),
DAG.getBoolConstant(false, dl, EltVT, VT));
}
SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Chains);
ReplaceValueWith(SDValue(N, 1), NewChain);
return DAG.getBuildVector(VT, dl, Scalars);
}
SDValue DAGTypeLegalizer::WidenVecOp_VECREDUCE(SDNode *N) {
SDLoc dl(N);
SDValue Op = GetWidenedVector(N->getOperand(0));
EVT OrigVT = N->getOperand(0).getValueType();
EVT WideVT = Op.getValueType();
EVT ElemVT = OrigVT.getVectorElementType();
SDNodeFlags Flags = N->getFlags();
unsigned Opc = N->getOpcode();
unsigned BaseOpc = ISD::getVecReduceBaseOpcode(Opc);
SDValue NeutralElem = DAG.getNeutralElement(BaseOpc, dl, ElemVT, Flags);
assert(NeutralElem && "Neutral element must exist");
unsigned OrigElts = OrigVT.getVectorMinNumElements();
unsigned WideElts = WideVT.getVectorMinNumElements();
if (WideVT.isScalableVector()) {
unsigned GCD = greatestCommonDivisor(OrigElts, WideElts);
EVT SplatVT = EVT::getVectorVT(*DAG.getContext(), ElemVT,
ElementCount::getScalable(GCD));
SDValue SplatNeutral = DAG.getSplatVector(SplatVT, dl, NeutralElem);
for (unsigned Idx = OrigElts; Idx < WideElts; Idx = Idx + GCD)
Op = DAG.getNode(ISD::INSERT_SUBVECTOR, dl, WideVT, Op, SplatNeutral,
DAG.getVectorIdxConstant(Idx, dl));
return DAG.getNode(Opc, dl, N->getValueType(0), Op, Flags);
}
for (unsigned Idx = OrigElts; Idx < WideElts; Idx++)
Op = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, WideVT, Op, NeutralElem,
DAG.getVectorIdxConstant(Idx, dl));
return DAG.getNode(Opc, dl, N->getValueType(0), Op, Flags);
}
SDValue DAGTypeLegalizer::WidenVecOp_VECREDUCE_SEQ(SDNode *N) {
SDLoc dl(N);
SDValue AccOp = N->getOperand(0);
SDValue VecOp = N->getOperand(1);
SDValue Op = GetWidenedVector(VecOp);
EVT OrigVT = VecOp.getValueType();
EVT WideVT = Op.getValueType();
EVT ElemVT = OrigVT.getVectorElementType();
SDNodeFlags Flags = N->getFlags();
unsigned Opc = N->getOpcode();
unsigned BaseOpc = ISD::getVecReduceBaseOpcode(Opc);
SDValue NeutralElem = DAG.getNeutralElement(BaseOpc, dl, ElemVT, Flags);
unsigned OrigElts = OrigVT.getVectorMinNumElements();
unsigned WideElts = WideVT.getVectorMinNumElements();
if (WideVT.isScalableVector()) {
unsigned GCD = greatestCommonDivisor(OrigElts, WideElts);
EVT SplatVT = EVT::getVectorVT(*DAG.getContext(), ElemVT,
ElementCount::getScalable(GCD));
SDValue SplatNeutral = DAG.getSplatVector(SplatVT, dl, NeutralElem);
for (unsigned Idx = OrigElts; Idx < WideElts; Idx = Idx + GCD)
Op = DAG.getNode(ISD::INSERT_SUBVECTOR, dl, WideVT, Op, SplatNeutral,
DAG.getVectorIdxConstant(Idx, dl));
return DAG.getNode(Opc, dl, N->getValueType(0), AccOp, Op, Flags);
}
for (unsigned Idx = OrigElts; Idx < WideElts; Idx++)
Op = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, WideVT, Op, NeutralElem,
DAG.getVectorIdxConstant(Idx, dl));
return DAG.getNode(Opc, dl, N->getValueType(0), AccOp, Op, Flags);
}
SDValue DAGTypeLegalizer::WidenVecOp_VP_REDUCE(SDNode *N) {
assert(N->isVPOpcode() && "Expected VP opcode");
SDLoc dl(N);
SDValue Op = GetWidenedVector(N->getOperand(1));
SDValue Mask = GetWidenedMask(N->getOperand(2),
Op.getValueType().getVectorElementCount());
return DAG.getNode(N->getOpcode(), dl, N->getValueType(0),
{N->getOperand(0), Op, Mask, N->getOperand(3)},
N->getFlags());
}
SDValue DAGTypeLegalizer::WidenVecOp_VSELECT(SDNode *N) {
EVT VT = N->getValueType(0);
assert(VT.isVector() && !VT.isPow2VectorType() && isTypeLegal(VT));
SDValue Cond = GetWidenedVector(N->getOperand(0));
SDValue LeftIn = DAG.WidenVector(N->getOperand(1), SDLoc(N));
SDValue RightIn = DAG.WidenVector(N->getOperand(2), SDLoc(N));
SDLoc DL(N);
SDValue Select = DAG.getNode(N->getOpcode(), DL, LeftIn.getValueType(), Cond,
LeftIn, RightIn);
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, Select,
DAG.getVectorIdxConstant(0, DL));
}
static Optional<EVT> findMemType(SelectionDAG &DAG, const TargetLowering &TLI,
unsigned Width, EVT WidenVT,
unsigned Align = 0, unsigned WidenEx = 0) {
EVT WidenEltVT = WidenVT.getVectorElementType();
const bool Scalable = WidenVT.isScalableVector();
unsigned WidenWidth = WidenVT.getSizeInBits().getKnownMinSize();
unsigned WidenEltWidth = WidenEltVT.getSizeInBits();
unsigned AlignInBits = Align*8;
EVT RetVT = WidenEltVT;
if (!Scalable && Width == WidenEltWidth)
return RetVT;
if (!Scalable) {
for (EVT MemVT : reverse(MVT::integer_valuetypes())) {
unsigned MemVTWidth = MemVT.getSizeInBits();
if (MemVT.getSizeInBits() <= WidenEltWidth)
break;
auto Action = TLI.getTypeAction(*DAG.getContext(), MemVT);
if ((Action == TargetLowering::TypeLegal ||
Action == TargetLowering::TypePromoteInteger) &&
(WidenWidth % MemVTWidth) == 0 &&
isPowerOf2_32(WidenWidth / MemVTWidth) &&
(MemVTWidth <= Width ||
(Align!=0 && MemVTWidth<=AlignInBits && MemVTWidth<=Width+WidenEx))) {
if (MemVTWidth == WidenWidth)
return MemVT;
RetVT = MemVT;
break;
}
}
}
for (EVT MemVT : reverse(MVT::vector_valuetypes())) {
if (Scalable != MemVT.isScalableVector())
continue;
unsigned MemVTWidth = MemVT.getSizeInBits().getKnownMinSize();
auto Action = TLI.getTypeAction(*DAG.getContext(), MemVT);
if ((Action == TargetLowering::TypeLegal ||
Action == TargetLowering::TypePromoteInteger) &&
WidenEltVT == MemVT.getVectorElementType() &&
(WidenWidth % MemVTWidth) == 0 &&
isPowerOf2_32(WidenWidth / MemVTWidth) &&
(MemVTWidth <= Width ||
(Align!=0 && MemVTWidth<=AlignInBits && MemVTWidth<=Width+WidenEx))) {
if (RetVT.getFixedSizeInBits() < MemVTWidth || MemVT == WidenVT)
return MemVT;
}
}
if (Scalable)
return None;
return RetVT;
}
static SDValue BuildVectorFromScalar(SelectionDAG& DAG, EVT VecTy,
SmallVectorImpl<SDValue> &LdOps,
unsigned Start, unsigned End) {
SDLoc dl(LdOps[Start]);
EVT LdTy = LdOps[Start].getValueType();
unsigned Width = VecTy.getSizeInBits();
unsigned NumElts = Width / LdTy.getSizeInBits();
EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), LdTy, NumElts);
unsigned Idx = 1;
SDValue VecOp = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, NewVecVT,LdOps[Start]);
for (unsigned i = Start + 1; i != End; ++i) {
EVT NewLdTy = LdOps[i].getValueType();
if (NewLdTy != LdTy) {
NumElts = Width / NewLdTy.getSizeInBits();
NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewLdTy, NumElts);
VecOp = DAG.getNode(ISD::BITCAST, dl, NewVecVT, VecOp);
Idx = Idx * LdTy.getSizeInBits() / NewLdTy.getSizeInBits();
LdTy = NewLdTy;
}
VecOp = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NewVecVT, VecOp, LdOps[i],
DAG.getVectorIdxConstant(Idx++, dl));
}
return DAG.getNode(ISD::BITCAST, dl, VecTy, VecOp);
}
SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVectorImpl<SDValue> &LdChain,
LoadSDNode *LD) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(),LD->getValueType(0));
EVT LdVT = LD->getMemoryVT();
SDLoc dl(LD);
assert(LdVT.isVector() && WidenVT.isVector());
assert(LdVT.isScalableVector() == WidenVT.isScalableVector());
assert(LdVT.getVectorElementType() == WidenVT.getVectorElementType());
SDValue Chain = LD->getChain();
SDValue BasePtr = LD->getBasePtr();
MachineMemOperand::Flags MMOFlags = LD->getMemOperand()->getFlags();
AAMDNodes AAInfo = LD->getAAInfo();
TypeSize LdWidth = LdVT.getSizeInBits();
TypeSize WidenWidth = WidenVT.getSizeInBits();
TypeSize WidthDiff = WidenWidth - LdWidth;
unsigned LdAlign =
(!LD->isSimple() || LdVT.isScalableVector()) ? 0 : LD->getAlign().value();
Optional<EVT> FirstVT =
findMemType(DAG, TLI, LdWidth.getKnownMinSize(), WidenVT, LdAlign,
WidthDiff.getKnownMinSize());
if (!FirstVT)
return SDValue();
SmallVector<EVT, 8> MemVTs;
TypeSize FirstVTWidth = FirstVT->getSizeInBits();
if (!TypeSize::isKnownLE(LdWidth, FirstVTWidth)) {
Optional<EVT> NewVT = FirstVT;
TypeSize RemainingWidth = LdWidth;
TypeSize NewVTWidth = FirstVTWidth;
do {
RemainingWidth -= NewVTWidth;
if (TypeSize::isKnownLT(RemainingWidth, NewVTWidth)) {
NewVT = findMemType(DAG, TLI, RemainingWidth.getKnownMinSize(), WidenVT,
LdAlign, WidthDiff.getKnownMinSize());
if (!NewVT)
return SDValue();
NewVTWidth = NewVT->getSizeInBits();
}
MemVTs.push_back(*NewVT);
} while (TypeSize::isKnownGT(RemainingWidth, NewVTWidth));
}
SDValue LdOp = DAG.getLoad(*FirstVT, dl, Chain, BasePtr, LD->getPointerInfo(),
LD->getOriginalAlign(), MMOFlags, AAInfo);
LdChain.push_back(LdOp.getValue(1));
if (MemVTs.empty()) {
assert(TypeSize::isKnownLE(LdWidth, FirstVTWidth));
if (!FirstVT->isVector()) {
unsigned NumElts =
WidenWidth.getFixedSize() / FirstVTWidth.getFixedSize();
EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), *FirstVT, NumElts);
SDValue VecOp = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, NewVecVT, LdOp);
return DAG.getNode(ISD::BITCAST, dl, WidenVT, VecOp);
}
if (FirstVT == WidenVT)
return LdOp;
assert(WidenWidth.getFixedSize() % FirstVTWidth.getFixedSize() == 0);
unsigned NumConcat =
WidenWidth.getFixedSize() / FirstVTWidth.getFixedSize();
SmallVector<SDValue, 16> ConcatOps(NumConcat);
SDValue UndefVal = DAG.getUNDEF(*FirstVT);
ConcatOps[0] = LdOp;
for (unsigned i = 1; i != NumConcat; ++i)
ConcatOps[i] = UndefVal;
return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, ConcatOps);
}
SmallVector<SDValue, 16> LdOps;
LdOps.push_back(LdOp);
uint64_t ScaledOffset = 0;
MachinePointerInfo MPI = LD->getPointerInfo();
IncrementPointer(cast<LoadSDNode>(LdOp), *FirstVT, MPI, BasePtr,
&ScaledOffset);
for (EVT MemVT : MemVTs) {
Align NewAlign = ScaledOffset == 0
? LD->getOriginalAlign()
: commonAlignment(LD->getAlign(), ScaledOffset);
SDValue L =
DAG.getLoad(MemVT, dl, Chain, BasePtr, MPI, NewAlign, MMOFlags, AAInfo);
LdOps.push_back(L);
LdChain.push_back(L.getValue(1));
IncrementPointer(cast<LoadSDNode>(L), MemVT, MPI, BasePtr, &ScaledOffset);
}
unsigned End = LdOps.size();
if (!LdOps[0].getValueType().isVector())
return BuildVectorFromScalar(DAG, WidenVT, LdOps, 0, End);
SmallVector<SDValue, 16> ConcatOps(End);
int i = End - 1;
int Idx = End;
EVT LdTy = LdOps[i].getValueType();
if (!LdTy.isVector()) {
for (--i; i >= 0; --i) {
LdTy = LdOps[i].getValueType();
if (LdTy.isVector())
break;
}
ConcatOps[--Idx] = BuildVectorFromScalar(DAG, LdTy, LdOps, i + 1, End);
}
ConcatOps[--Idx] = LdOps[i];
for (--i; i >= 0; --i) {
EVT NewLdTy = LdOps[i].getValueType();
if (NewLdTy != LdTy) {
TypeSize LdTySize = LdTy.getSizeInBits();
TypeSize NewLdTySize = NewLdTy.getSizeInBits();
assert(NewLdTySize.isScalable() == LdTySize.isScalable() &&
NewLdTySize.isKnownMultipleOf(LdTySize.getKnownMinSize()));
unsigned NumOps =
NewLdTySize.getKnownMinSize() / LdTySize.getKnownMinSize();
SmallVector<SDValue, 16> WidenOps(NumOps);
unsigned j = 0;
for (; j != End-Idx; ++j)
WidenOps[j] = ConcatOps[Idx+j];
for (; j != NumOps; ++j)
WidenOps[j] = DAG.getUNDEF(LdTy);
ConcatOps[End-1] = DAG.getNode(ISD::CONCAT_VECTORS, dl, NewLdTy,
WidenOps);
Idx = End - 1;
LdTy = NewLdTy;
}
ConcatOps[--Idx] = LdOps[i];
}
if (WidenWidth == LdTy.getSizeInBits() * (End - Idx))
return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT,
makeArrayRef(&ConcatOps[Idx], End - Idx));
unsigned NumOps =
WidenWidth.getKnownMinSize() / LdTy.getSizeInBits().getKnownMinSize();
SmallVector<SDValue, 16> WidenOps(NumOps);
SDValue UndefVal = DAG.getUNDEF(LdTy);
{
unsigned i = 0;
for (; i != End-Idx; ++i)
WidenOps[i] = ConcatOps[Idx+i];
for (; i != NumOps; ++i)
WidenOps[i] = UndefVal;
}
return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, WidenOps);
}
SDValue
DAGTypeLegalizer::GenWidenVectorExtLoads(SmallVectorImpl<SDValue> &LdChain,
LoadSDNode *LD,
ISD::LoadExtType ExtType) {
EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(),LD->getValueType(0));
EVT LdVT = LD->getMemoryVT();
SDLoc dl(LD);
assert(LdVT.isVector() && WidenVT.isVector());
assert(LdVT.isScalableVector() == WidenVT.isScalableVector());
SDValue Chain = LD->getChain();
SDValue BasePtr = LD->getBasePtr();
MachineMemOperand::Flags MMOFlags = LD->getMemOperand()->getFlags();
AAMDNodes AAInfo = LD->getAAInfo();
if (LdVT.isScalableVector())
report_fatal_error("Generating widen scalable extending vector loads is "
"not yet supported");
EVT EltVT = WidenVT.getVectorElementType();
EVT LdEltVT = LdVT.getVectorElementType();
unsigned NumElts = LdVT.getVectorNumElements();
unsigned WidenNumElts = WidenVT.getVectorNumElements();
SmallVector<SDValue, 16> Ops(WidenNumElts);
unsigned Increment = LdEltVT.getSizeInBits() / 8;
Ops[0] =
DAG.getExtLoad(ExtType, dl, EltVT, Chain, BasePtr, LD->getPointerInfo(),
LdEltVT, LD->getOriginalAlign(), MMOFlags, AAInfo);
LdChain.push_back(Ops[0].getValue(1));
unsigned i = 0, Offset = Increment;
for (i=1; i < NumElts; ++i, Offset += Increment) {
SDValue NewBasePtr =
DAG.getObjectPtrOffset(dl, BasePtr, TypeSize::Fixed(Offset));
Ops[i] = DAG.getExtLoad(ExtType, dl, EltVT, Chain, NewBasePtr,
LD->getPointerInfo().getWithOffset(Offset), LdEltVT,
LD->getOriginalAlign(), MMOFlags, AAInfo);
LdChain.push_back(Ops[i].getValue(1));
}
SDValue UndefVal = DAG.getUNDEF(EltVT);
for (; i != WidenNumElts; ++i)
Ops[i] = UndefVal;
return DAG.getBuildVector(WidenVT, dl, Ops);
}
bool DAGTypeLegalizer::GenWidenVectorStores(SmallVectorImpl<SDValue> &StChain,
StoreSDNode *ST) {
SDValue Chain = ST->getChain();
SDValue BasePtr = ST->getBasePtr();
MachineMemOperand::Flags MMOFlags = ST->getMemOperand()->getFlags();
AAMDNodes AAInfo = ST->getAAInfo();
SDValue ValOp = GetWidenedVector(ST->getValue());
SDLoc dl(ST);
EVT StVT = ST->getMemoryVT();
TypeSize StWidth = StVT.getSizeInBits();
EVT ValVT = ValOp.getValueType();
TypeSize ValWidth = ValVT.getSizeInBits();
EVT ValEltVT = ValVT.getVectorElementType();
unsigned ValEltWidth = ValEltVT.getFixedSizeInBits();
assert(StVT.getVectorElementType() == ValEltVT);
assert(StVT.isScalableVector() == ValVT.isScalableVector() &&
"Mismatch between store and value types");
int Idx = 0;
MachinePointerInfo MPI = ST->getPointerInfo();
uint64_t ScaledOffset = 0;
SmallVector<std::pair<EVT, unsigned>, 4> MemVTs;
while (StWidth.isNonZero()) {
Optional<EVT> NewVT =
findMemType(DAG, TLI, StWidth.getKnownMinSize(), ValVT);
if (!NewVT)
return false;
MemVTs.push_back({*NewVT, 0});
TypeSize NewVTWidth = NewVT->getSizeInBits();
do {
StWidth -= NewVTWidth;
MemVTs.back().second++;
} while (StWidth.isNonZero() && TypeSize::isKnownGE(StWidth, NewVTWidth));
}
for (const auto &Pair : MemVTs) {
EVT NewVT = Pair.first;
unsigned Count = Pair.second;
TypeSize NewVTWidth = NewVT.getSizeInBits();
if (NewVT.isVector()) {
unsigned NumVTElts = NewVT.getVectorMinNumElements();
do {
Align NewAlign = ScaledOffset == 0
? ST->getOriginalAlign()
: commonAlignment(ST->getAlign(), ScaledOffset);
SDValue EOp = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, NewVT, ValOp,
DAG.getVectorIdxConstant(Idx, dl));
SDValue PartStore = DAG.getStore(Chain, dl, EOp, BasePtr, MPI, NewAlign,
MMOFlags, AAInfo);
StChain.push_back(PartStore);
Idx += NumVTElts;
IncrementPointer(cast<StoreSDNode>(PartStore), NewVT, MPI, BasePtr,
&ScaledOffset);
} while (--Count);
} else {
unsigned NumElts = ValWidth.getFixedSize() / NewVTWidth.getFixedSize();
EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewVT, NumElts);
SDValue VecOp = DAG.getNode(ISD::BITCAST, dl, NewVecVT, ValOp);
Idx = Idx * ValEltWidth / NewVTWidth.getFixedSize();
do {
SDValue EOp = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NewVT, VecOp,
DAG.getVectorIdxConstant(Idx++, dl));
SDValue PartStore =
DAG.getStore(Chain, dl, EOp, BasePtr, MPI, ST->getOriginalAlign(),
MMOFlags, AAInfo);
StChain.push_back(PartStore);
IncrementPointer(cast<StoreSDNode>(PartStore), NewVT, MPI, BasePtr);
} while (--Count);
Idx = Idx * NewVTWidth.getFixedSize() / ValEltWidth;
}
}
return true;
}
SDValue DAGTypeLegalizer::ModifyToType(SDValue InOp, EVT NVT,
bool FillWithZeroes) {
EVT InVT = InOp.getValueType();
assert(InVT.getVectorElementType() == NVT.getVectorElementType() &&
"input and widen element type must match");
assert(InVT.isScalableVector() == NVT.isScalableVector() &&
"cannot modify scalable vectors in this way");
SDLoc dl(InOp);
if (InVT == NVT)
return InOp;
ElementCount InEC = InVT.getVectorElementCount();
ElementCount WidenEC = NVT.getVectorElementCount();
if (WidenEC.hasKnownScalarFactor(InEC)) {
unsigned NumConcat = WidenEC.getKnownScalarFactor(InEC);
SmallVector<SDValue, 16> Ops(NumConcat);
SDValue FillVal = FillWithZeroes ? DAG.getConstant(0, dl, InVT) :
DAG.getUNDEF(InVT);
Ops[0] = InOp;
for (unsigned i = 1; i != NumConcat; ++i)
Ops[i] = FillVal;
return DAG.getNode(ISD::CONCAT_VECTORS, dl, NVT, Ops);
}
if (InEC.hasKnownScalarFactor(WidenEC))
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, NVT, InOp,
DAG.getVectorIdxConstant(0, dl));
assert(!InVT.isScalableVector() && !NVT.isScalableVector() &&
"Scalable vectors should have been handled already.");
unsigned InNumElts = InEC.getFixedValue();
unsigned WidenNumElts = WidenEC.getFixedValue();
SmallVector<SDValue, 16> Ops(WidenNumElts);
EVT EltVT = NVT.getVectorElementType();
unsigned MinNumElts = std::min(WidenNumElts, InNumElts);
unsigned Idx;
for (Idx = 0; Idx < MinNumElts; ++Idx)
Ops[Idx] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp,
DAG.getVectorIdxConstant(Idx, dl));
SDValue FillVal = FillWithZeroes ? DAG.getConstant(0, dl, EltVT) :
DAG.getUNDEF(EltVT);
for ( ; Idx < WidenNumElts; ++Idx)
Ops[Idx] = FillVal;
return DAG.getBuildVector(NVT, dl, Ops);
}