#include "VEISelLowering.h"
#include "MCTargetDesc/VEMCExpr.h"
#include "VECustomDAG.h"
#include "VEInstrBuilder.h"
#include "VEMachineFunctionInfo.h"
#include "VERegisterInfo.h"
#include "VETargetMachine.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
using namespace llvm;
#define DEBUG_TYPE "ve-lower"
#include "VEGenCallingConv.inc"
CCAssignFn *getReturnCC(CallingConv::ID CallConv) {
switch (CallConv) {
default:
return RetCC_VE_C;
case CallingConv::Fast:
return RetCC_VE_Fast;
}
}
CCAssignFn *getParamCC(CallingConv::ID CallConv, bool IsVarArg) {
if (IsVarArg)
return CC_VE2;
switch (CallConv) {
default:
return CC_VE_C;
case CallingConv::Fast:
return CC_VE_Fast;
}
}
bool VETargetLowering::CanLowerReturn(
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
CCAssignFn *RetCC = getReturnCC(CallConv);
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
return CCInfo.CheckReturn(Outs, RetCC);
}
static const MVT AllVectorVTs[] = {MVT::v256i32, MVT::v512i32, MVT::v256i64,
MVT::v256f32, MVT::v512f32, MVT::v256f64};
static const MVT AllMaskVTs[] = {MVT::v256i1, MVT::v512i1};
static const MVT AllPackedVTs[] = {MVT::v512i32, MVT::v512f32};
void VETargetLowering::initRegisterClasses() {
addRegisterClass(MVT::i32, &VE::I32RegClass);
addRegisterClass(MVT::i64, &VE::I64RegClass);
addRegisterClass(MVT::f32, &VE::F32RegClass);
addRegisterClass(MVT::f64, &VE::I64RegClass);
addRegisterClass(MVT::f128, &VE::F128RegClass);
if (Subtarget->enableVPU()) {
for (MVT VecVT : AllVectorVTs)
addRegisterClass(VecVT, &VE::V64RegClass);
addRegisterClass(MVT::v256i1, &VE::VMRegClass);
addRegisterClass(MVT::v512i1, &VE::VM512RegClass);
}
}
void VETargetLowering::initSPUActions() {
const auto &TM = getTargetMachine();
for (MVT VT : MVT::integer_valuetypes()) {
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);
setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote);
setTruncStoreAction(VT, MVT::i1, Expand);
}
for (MVT FPVT : MVT::fp_valuetypes()) {
for (MVT OtherFPVT : MVT::fp_valuetypes()) {
setLoadExtAction(ISD::EXTLOAD, FPVT, OtherFPVT, Expand);
setTruncStoreAction(FPVT, OtherFPVT, Expand);
}
}
setOperationAction(ISD::LOAD, MVT::f128, Custom);
setOperationAction(ISD::STORE, MVT::f128, Custom);
MVT PtrVT = MVT::getIntegerVT(TM.getPointerSizeInBits(0));
setOperationAction(ISD::BlockAddress, PtrVT, Custom);
setOperationAction(ISD::GlobalAddress, PtrVT, Custom);
setOperationAction(ISD::GlobalTLSAddress, PtrVT, Custom);
setOperationAction(ISD::ConstantPool, PtrVT, Custom);
setOperationAction(ISD::JumpTable, PtrVT, Custom);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAARG, MVT::Other, Custom);
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
for (MVT IntVT : {MVT::i32, MVT::i64}) {
setOperationAction(ISD::UREM, IntVT, Expand);
setOperationAction(ISD::SREM, IntVT, Expand);
setOperationAction(ISD::SDIVREM, IntVT, Expand);
setOperationAction(ISD::UDIVREM, IntVT, Expand);
setOperationAction(ISD::SHL_PARTS, IntVT, Expand);
setOperationAction(ISD::SRA_PARTS, IntVT, Expand);
setOperationAction(ISD::SRL_PARTS, IntVT, Expand);
setOperationAction(ISD::MULHU, IntVT, Expand);
setOperationAction(ISD::MULHS, IntVT, Expand);
setOperationAction(ISD::UMUL_LOHI, IntVT, Expand);
setOperationAction(ISD::SMUL_LOHI, IntVT, Expand);
setOperationAction(ISD::CTTZ, IntVT, Expand);
setOperationAction(ISD::ROTL, IntVT, Expand);
setOperationAction(ISD::ROTR, IntVT, Expand);
setOperationAction(ISD::BSWAP, IntVT, Legal);
LegalizeAction Act = (IntVT == MVT::i32) ? Promote : Legal;
setOperationAction(ISD::BITREVERSE, IntVT, Act);
setOperationAction(ISD::CTLZ, IntVT, Act);
setOperationAction(ISD::CTLZ_ZERO_UNDEF, IntVT, Act);
setOperationAction(ISD::CTPOP, IntVT, Act);
setOperationAction(ISD::AND, IntVT, Act);
setOperationAction(ISD::OR, IntVT, Act);
setOperationAction(ISD::XOR, IntVT, Act);
}
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Promote); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Promote); setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand);
setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
for (MVT FPVT : MVT::fp_valuetypes()) {
setOperationAction(ISD::FP16_TO_FP, FPVT, Expand);
setOperationAction(ISD::FP_TO_FP16, FPVT, Expand);
}
for (MVT VT : MVT::fp_valuetypes()) {
setOperationAction(ISD::FNEG, VT, Expand);
setOperationAction(ISD::FREM, VT, Expand);
}
setOperationAction(ISD::FDIV, MVT::f128, Expand);
for (MVT FPVT : {MVT::f32, MVT::f64}) {
setOperationAction(ISD::ConstantFP, FPVT, Legal);
}
for (MVT VT : MVT::fp_valuetypes()) {
setOperationAction(ISD::FABS, VT, Expand);
setOperationAction(ISD::FCOPYSIGN, VT, Expand);
setOperationAction(ISD::FCOS, VT, Expand);
setOperationAction(ISD::FSIN, VT, Expand);
setOperationAction(ISD::FSQRT, VT, Expand);
}
setMaxAtomicSizeInBitsSupported(64);
setMinCmpXchgSizeInBits(32);
setSupportsUnalignedAtomics(false);
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::ATOMIC_SWAP, VT, Custom);
setOperationAction(ISD::ATOMIC_LOAD_ADD, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_SUB, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_AND, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_OR, VT, Expand);
setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_CLR, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_XOR, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand);
}
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
if (TM.Options.ExceptionModel == ExceptionHandling::SjLj)
setLibcallName(RTLIB::UNWIND_RESUME, "_Unwind_SjLj_Resume");
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
}
void VETargetLowering::initVPUActions() {
for (MVT LegalMaskVT : AllMaskVTs)
setOperationAction(ISD::BUILD_VECTOR, LegalMaskVT, Custom);
for (unsigned Opc : {ISD::AND, ISD::OR, ISD::XOR})
setOperationAction(Opc, MVT::v512i1, Custom);
for (MVT LegalVecVT : AllVectorVTs) {
setOperationAction(ISD::BUILD_VECTOR, LegalVecVT, Custom);
setOperationAction(ISD::INSERT_VECTOR_ELT, LegalVecVT, Legal);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, LegalVecVT, Legal);
#define HANDLE_VP_TO_VVP(VP_OPC, VVP_NAME) \
setOperationAction(ISD::VP_OPC, LegalVecVT, Custom);
#define ADD_VVP_OP(VVP_NAME, ISD_NAME) \
setOperationAction(ISD::ISD_NAME, LegalVecVT, Custom);
setOperationAction(ISD::EXPERIMENTAL_VP_STRIDED_LOAD, LegalVecVT, Custom);
setOperationAction(ISD::EXPERIMENTAL_VP_STRIDED_STORE, LegalVecVT, Custom);
#include "VVPNodes.def"
}
for (MVT LegalPackedVT : AllPackedVTs) {
setOperationAction(ISD::INSERT_VECTOR_ELT, LegalPackedVT, Custom);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, LegalPackedVT, Custom);
}
for (MVT VT : MVT::vector_valuetypes()) {
MVT ElemVT = VT.getVectorElementType();
unsigned ElemBits = ElemVT.getScalarSizeInBits();
if (ElemBits != 32 && ElemBits != 64)
continue;
for (unsigned MemOpc : {ISD::MLOAD, ISD::MSTORE, ISD::LOAD, ISD::STORE})
setOperationAction(MemOpc, VT, Custom);
const ISD::NodeType IntReductionOCs[] = {
ISD::VECREDUCE_ADD, ISD::VECREDUCE_MUL, ISD::VECREDUCE_AND,
ISD::VECREDUCE_OR, ISD::VECREDUCE_XOR, ISD::VECREDUCE_SMIN,
ISD::VECREDUCE_SMAX, ISD::VECREDUCE_UMIN, ISD::VECREDUCE_UMAX};
for (unsigned IntRedOpc : IntReductionOCs)
setOperationAction(IntRedOpc, VT, Custom);
}
for (MVT MaskVT : AllMaskVTs) {
setOperationAction(ISD::STORE, MaskVT, Custom);
setOperationAction(ISD::LOAD, MaskVT, Custom);
}
}
SDValue
VETargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SDLoc &DL, SelectionDAG &DAG) const {
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
CCInfo.AnalyzeReturn(Outs, getReturnCC(CallConv));
SDValue Flag;
SmallVector<SDValue, 4> RetOps(1, Chain);
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
assert(VA.isRegLoc() && "Can only return in registers!");
assert(!VA.needsCustom() && "Unexpected custom lowering");
SDValue OutVal = OutVals[i];
switch (VA.getLocInfo()) {
case CCValAssign::Full:
break;
case CCValAssign::SExt:
OutVal = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), OutVal);
break;
case CCValAssign::ZExt:
OutVal = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), OutVal);
break;
case CCValAssign::AExt:
OutVal = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), OutVal);
break;
case CCValAssign::BCvt: {
assert(VA.getLocVT() == MVT::i64);
assert(VA.getValVT() == MVT::f32);
SDValue Undef = SDValue(
DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i64), 0);
SDValue Sub_f32 = DAG.getTargetConstant(VE::sub_f32, DL, MVT::i32);
OutVal = SDValue(DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL,
MVT::i64, Undef, OutVal, Sub_f32),
0);
break;
}
default:
llvm_unreachable("Unknown loc info!");
}
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVal, Flag);
Flag = Chain.getValue(1);
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
}
RetOps[0] = Chain;
if (Flag.getNode())
RetOps.push_back(Flag);
return DAG.getNode(VEISD::RET_FLAG, DL, MVT::Other, RetOps);
}
SDValue VETargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
unsigned ArgsBaseOffset = Subtarget->getRsaSize();
unsigned ArgsPreserved = 64;
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
CCInfo.AllocateStack(ArgsPreserved, Align(8));
CCInfo.AnalyzeFormalArguments(Ins, getParamCC(CallConv, false));
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
assert(!VA.needsCustom() && "Unexpected custom lowering");
if (VA.isRegLoc()) {
Register VReg =
MF.addLiveIn(VA.getLocReg(), getRegClassFor(VA.getLocVT()));
SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT());
switch (VA.getLocInfo()) {
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Arg,
DAG.getValueType(VA.getValVT()));
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Arg,
DAG.getValueType(VA.getValVT()));
break;
case CCValAssign::BCvt: {
assert(VA.getLocVT() == MVT::i64);
assert(VA.getValVT() == MVT::f32);
SDValue Sub_f32 = DAG.getTargetConstant(VE::sub_f32, DL, MVT::i32);
Arg = SDValue(DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
MVT::f32, Arg, Sub_f32),
0);
break;
}
default:
break;
}
if (VA.isExtInLoc())
Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Arg);
InVals.push_back(Arg);
continue;
}
assert(VA.isMemLoc());
unsigned Offset = VA.getLocMemOffset() + ArgsBaseOffset;
unsigned ValSize = VA.getValVT().getSizeInBits() / 8;
if (VA.getValVT() == MVT::f32)
Offset += 4;
int FI = MF.getFrameInfo().CreateFixedObject(ValSize, Offset, true);
InVals.push_back(
DAG.getLoad(VA.getValVT(), DL, Chain,
DAG.getFrameIndex(FI, getPointerTy(MF.getDataLayout())),
MachinePointerInfo::getFixedStack(MF, FI)));
}
if (!IsVarArg)
return Chain;
unsigned ArgOffset = ArgLocs.size() * 8;
VEMachineFunctionInfo *FuncInfo = MF.getInfo<VEMachineFunctionInfo>();
FuncInfo->setVarArgsFrameOffset(ArgOffset + ArgsBaseOffset);
return Chain;
}
Register VETargetLowering::getRegisterByName(const char *RegName, LLT VT,
const MachineFunction &MF) const {
Register Reg = StringSwitch<Register>(RegName)
.Case("sp", VE::SX11) .Case("fp", VE::SX9) .Case("sl", VE::SX8) .Case("lr", VE::SX10) .Case("tp", VE::SX14) .Case("outer", VE::SX12) .Case("info", VE::SX17) .Case("got", VE::SX15) .Case("plt", VE::SX16) .Default(0);
if (Reg)
return Reg;
report_fatal_error("Invalid register name global variable");
}
SDValue VETargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
SelectionDAG &DAG = CLI.DAG;
SDLoc DL = CLI.DL;
SDValue Chain = CLI.Chain;
auto PtrVT = getPointerTy(DAG.getDataLayout());
CLI.IsTailCall = false;
unsigned ArgsBaseOffset = Subtarget->getRsaSize();
unsigned ArgsPreserved = 8 * 8u;
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
CCInfo.AllocateStack(ArgsPreserved, Align(8));
CCInfo.AnalyzeCallOperands(CLI.Outs, getParamCC(CLI.CallConv, false));
bool UseBoth = CLI.IsVarArg;
SmallVector<CCValAssign, 16> ArgLocs2;
CCState CCInfo2(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(),
ArgLocs2, *DAG.getContext());
if (UseBoth)
CCInfo2.AnalyzeCallOperands(CLI.Outs, getParamCC(CLI.CallConv, true));
unsigned ArgsSize = CCInfo.getNextStackOffset();
ArgsSize = alignTo(ArgsSize, 16);
Chain = DAG.getCALLSEQ_START(Chain, ArgsSize, 0, DL);
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
SmallVector<SDValue, 8> MemOpChains;
SDValue Callee = CLI.Callee;
bool IsPICCall = isPositionIndependent();
const TargetMachine &TM = DAG.getTarget();
const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
const GlobalValue *GV = nullptr;
auto *CalleeG = dyn_cast<GlobalAddressSDNode>(Callee);
if (CalleeG)
GV = CalleeG->getGlobal();
bool Local = TM.shouldAssumeDSOLocal(*Mod, GV);
bool UsePlt = !Local;
MachineFunction &MF = DAG.getMachineFunction();
if (CalleeG) {
if (IsPICCall) {
if (UsePlt)
Subtarget->getInstrInfo()->getGlobalBaseReg(&MF);
Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, 0);
Callee = DAG.getNode(VEISD::GETFUNPLT, DL, PtrVT, Callee);
} else {
Callee =
makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
}
} else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
if (IsPICCall) {
if (UsePlt)
Subtarget->getInstrInfo()->getGlobalBaseReg(&MF);
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0);
Callee = DAG.getNode(VEISD::GETFUNPLT, DL, PtrVT, Callee);
} else {
Callee =
makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
}
}
RegsToPass.push_back(std::make_pair(VE::SX12, Callee));
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
SDValue Arg = CLI.OutVals[i];
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unknown location info!");
case CCValAssign::Full:
break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg);
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg);
break;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
break;
case CCValAssign::BCvt: {
assert(VA.getLocVT() == MVT::i64);
assert(VA.getValVT() == MVT::f32);
SDValue Undef = SDValue(
DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i64), 0);
SDValue Sub_f32 = DAG.getTargetConstant(VE::sub_f32, DL, MVT::i32);
Arg = SDValue(DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL,
MVT::i64, Undef, Arg, Sub_f32),
0);
break;
}
}
if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
if (!UseBoth)
continue;
VA = ArgLocs2[i];
}
assert(VA.isMemLoc());
SDValue StackPtr = DAG.getRegister(VE::SX11, PtrVT);
SDValue PtrOff =
DAG.getIntPtrConstant(VA.getLocMemOffset() + ArgsBaseOffset, DL);
PtrOff = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, PtrOff);
MemOpChains.push_back(
DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo()));
}
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
SDValue InGlue;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[i].first,
RegsToPass[i].second, InGlue);
InGlue = Chain.getValue(1);
}
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
RegsToPass[i].second.getValueType()));
const VERegisterInfo *TRI = Subtarget->getRegisterInfo();
const uint32_t *Mask =
TRI->getCallPreservedMask(DAG.getMachineFunction(), CLI.CallConv);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));
if (InGlue.getNode())
Ops.push_back(InGlue);
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
Chain = DAG.getNode(VEISD::CALL, DL, NodeTys, Ops);
InGlue = Chain.getValue(1);
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, DL, true),
DAG.getIntPtrConstant(0, DL, true), InGlue, DL);
InGlue = Chain.getValue(1);
SmallVector<CCValAssign, 16> RVLocs;
CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && !CLI.CB)
CLI.Ins[0].Flags.setInReg();
RVInfo.AnalyzeCallResult(CLI.Ins, getReturnCC(CLI.CallConv));
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
assert(!VA.needsCustom() && "Unexpected custom lowering");
Register Reg = VA.getLocReg();
SDValue RV;
if (RegisterSDNode *SrcReg = dyn_cast<RegisterSDNode>(Chain.getOperand(1)))
if (SrcReg->getReg() == Reg && Chain->getOpcode() == ISD::CopyFromReg)
RV = Chain.getValue(0);
if (!RV.getNode()) {
RV = DAG.getCopyFromReg(Chain, DL, Reg, RVLocs[i].getLocVT(), InGlue);
Chain = RV.getValue(1);
InGlue = Chain.getValue(2);
}
switch (VA.getLocInfo()) {
case CCValAssign::SExt:
RV = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), RV,
DAG.getValueType(VA.getValVT()));
break;
case CCValAssign::ZExt:
RV = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), RV,
DAG.getValueType(VA.getValVT()));
break;
case CCValAssign::BCvt: {
assert(VA.getLocVT() == MVT::i64);
assert(VA.getValVT() == MVT::f32);
SDValue Sub_f32 = DAG.getTargetConstant(VE::sub_f32, DL, MVT::i32);
RV = SDValue(DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
MVT::f32, RV, Sub_f32),
0);
break;
}
default:
break;
}
if (VA.isExtInLoc())
RV = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), RV);
InVals.push_back(RV);
}
return Chain;
}
bool VETargetLowering::isOffsetFoldingLegal(
const GlobalAddressSDNode *GA) const {
return false;
}
bool VETargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const {
return VT == MVT::f32 || VT == MVT::f64;
}
bool VETargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
unsigned AddrSpace,
Align A,
MachineMemOperand::Flags,
bool *Fast) const {
if (Fast) {
*Fast = true;
}
return true;
}
VETargetLowering::VETargetLowering(const TargetMachine &TM,
const VESubtarget &STI)
: TargetLowering(TM), Subtarget(&STI) {
setBooleanContents(ZeroOrOneBooleanContent);
setBooleanVectorContents(ZeroOrOneBooleanContent);
initRegisterClasses();
initSPUActions();
initVPUActions();
setStackPointerRegisterToSaveRestore(VE::SX11);
setTargetDAGCombine(ISD::TRUNCATE);
setMinFunctionAlignment(Align(16));
setMinStackArgumentAlignment(Align(8));
computeRegisterProperties(Subtarget->getRegisterInfo());
}
const char *VETargetLowering::getTargetNodeName(unsigned Opcode) const {
#define TARGET_NODE_CASE(NAME) \
case VEISD::NAME: \
return "VEISD::" #NAME;
switch ((VEISD::NodeType)Opcode) {
case VEISD::FIRST_NUMBER:
break;
TARGET_NODE_CASE(CALL)
TARGET_NODE_CASE(EH_SJLJ_LONGJMP)
TARGET_NODE_CASE(EH_SJLJ_SETJMP)
TARGET_NODE_CASE(EH_SJLJ_SETUP_DISPATCH)
TARGET_NODE_CASE(GETFUNPLT)
TARGET_NODE_CASE(GETSTACKTOP)
TARGET_NODE_CASE(GETTLSADDR)
TARGET_NODE_CASE(GLOBAL_BASE_REG)
TARGET_NODE_CASE(Hi)
TARGET_NODE_CASE(Lo)
TARGET_NODE_CASE(MEMBARRIER)
TARGET_NODE_CASE(RET_FLAG)
TARGET_NODE_CASE(TS1AM)
TARGET_NODE_CASE(VEC_UNPACK_LO)
TARGET_NODE_CASE(VEC_UNPACK_HI)
TARGET_NODE_CASE(VEC_PACK)
TARGET_NODE_CASE(VEC_BROADCAST)
TARGET_NODE_CASE(REPL_I32)
TARGET_NODE_CASE(REPL_F32)
TARGET_NODE_CASE(LEGALAVL)
#define ADD_VVP_OP(VVP_NAME, ...) TARGET_NODE_CASE(VVP_NAME)
#include "VVPNodes.def"
}
#undef TARGET_NODE_CASE
return nullptr;
}
EVT VETargetLowering::getSetCCResultType(const DataLayout &, LLVMContext &,
EVT VT) const {
return MVT::i32;
}
SDValue VETargetLowering::withTargetFlags(SDValue Op, unsigned TF,
SelectionDAG &DAG) const {
if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op))
return DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(GA),
GA->getValueType(0), GA->getOffset(), TF);
if (const BlockAddressSDNode *BA = dyn_cast<BlockAddressSDNode>(Op))
return DAG.getTargetBlockAddress(BA->getBlockAddress(), Op.getValueType(),
0, TF);
if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Op))
return DAG.getTargetConstantPool(CP->getConstVal(), CP->getValueType(0),
CP->getAlign(), CP->getOffset(), TF);
if (const ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Op))
return DAG.getTargetExternalSymbol(ES->getSymbol(), ES->getValueType(0),
TF);
if (const JumpTableSDNode *JT = dyn_cast<JumpTableSDNode>(Op))
return DAG.getTargetJumpTable(JT->getIndex(), JT->getValueType(0), TF);
llvm_unreachable("Unhandled address SDNode");
}
SDValue VETargetLowering::makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF,
SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT VT = Op.getValueType();
SDValue Hi = DAG.getNode(VEISD::Hi, DL, VT, withTargetFlags(Op, HiTF, DAG));
SDValue Lo = DAG.getNode(VEISD::Lo, DL, VT, withTargetFlags(Op, LoTF, DAG));
return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
}
SDValue VETargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT PtrVT = Op.getValueType();
if (isPositionIndependent()) {
auto GlobalN = dyn_cast<GlobalAddressSDNode>(Op);
if (isa<ConstantPoolSDNode>(Op) || isa<JumpTableSDNode>(Op) ||
(GlobalN && GlobalN->getGlobal()->hasLocalLinkage())) {
SDValue HiLo = makeHiLoPair(Op, VEMCExpr::VK_VE_GOTOFF_HI32,
VEMCExpr::VK_VE_GOTOFF_LO32, DAG);
SDValue GlobalBase = DAG.getNode(VEISD::GLOBAL_BASE_REG, DL, PtrVT);
return DAG.getNode(ISD::ADD, DL, PtrVT, GlobalBase, HiLo);
}
SDValue HiLo = makeHiLoPair(Op, VEMCExpr::VK_VE_GOT_HI32,
VEMCExpr::VK_VE_GOT_LO32, DAG);
SDValue GlobalBase = DAG.getNode(VEISD::GLOBAL_BASE_REG, DL, PtrVT);
SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, PtrVT, GlobalBase, HiLo);
return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), AbsAddr,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
}
switch (getTargetMachine().getCodeModel()) {
default:
llvm_unreachable("Unsupported absolute code model");
case CodeModel::Small:
case CodeModel::Medium:
case CodeModel::Large:
return makeHiLoPair(Op, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
}
}
Instruction *VETargetLowering::emitLeadingFence(IRBuilderBase &Builder,
Instruction *Inst,
AtomicOrdering Ord) const {
switch (Ord) {
case AtomicOrdering::NotAtomic:
case AtomicOrdering::Unordered:
llvm_unreachable("Invalid fence: unordered/non-atomic");
case AtomicOrdering::Monotonic:
case AtomicOrdering::Acquire:
return nullptr; case AtomicOrdering::Release:
case AtomicOrdering::AcquireRelease:
return Builder.CreateFence(AtomicOrdering::Release);
case AtomicOrdering::SequentiallyConsistent:
if (!Inst->hasAtomicStore())
return nullptr; return Builder.CreateFence(AtomicOrdering::SequentiallyConsistent);
}
llvm_unreachable("Unknown fence ordering in emitLeadingFence");
}
Instruction *VETargetLowering::emitTrailingFence(IRBuilderBase &Builder,
Instruction *Inst,
AtomicOrdering Ord) const {
switch (Ord) {
case AtomicOrdering::NotAtomic:
case AtomicOrdering::Unordered:
llvm_unreachable("Invalid fence: unordered/not-atomic");
case AtomicOrdering::Monotonic:
case AtomicOrdering::Release:
return nullptr; case AtomicOrdering::Acquire:
case AtomicOrdering::AcquireRelease:
return Builder.CreateFence(AtomicOrdering::Acquire);
case AtomicOrdering::SequentiallyConsistent:
return Builder.CreateFence(AtomicOrdering::SequentiallyConsistent);
}
llvm_unreachable("Unknown fence ordering in emitTrailingFence");
}
SDValue VETargetLowering::lowerATOMIC_FENCE(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
AtomicOrdering FenceOrdering = static_cast<AtomicOrdering>(
cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue());
SyncScope::ID FenceSSID = static_cast<SyncScope::ID>(
cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue());
if (FenceSSID == SyncScope::System) {
switch (FenceOrdering) {
case AtomicOrdering::NotAtomic:
case AtomicOrdering::Unordered:
case AtomicOrdering::Monotonic:
break;
case AtomicOrdering::Acquire:
return SDValue(DAG.getMachineNode(VE::FENCEM, DL, MVT::Other,
DAG.getTargetConstant(2, DL, MVT::i32),
Op.getOperand(0)),
0);
case AtomicOrdering::Release:
return SDValue(DAG.getMachineNode(VE::FENCEM, DL, MVT::Other,
DAG.getTargetConstant(1, DL, MVT::i32),
Op.getOperand(0)),
0);
case AtomicOrdering::AcquireRelease:
case AtomicOrdering::SequentiallyConsistent:
return SDValue(DAG.getMachineNode(VE::FENCEM, DL, MVT::Other,
DAG.getTargetConstant(3, DL, MVT::i32),
Op.getOperand(0)),
0);
}
}
return DAG.getNode(VEISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
}
TargetLowering::AtomicExpansionKind
VETargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
if (AI->getOperation() == AtomicRMWInst::Xchg) {
return AtomicExpansionKind::None;
}
return AtomicExpansionKind::CmpXChg;
}
static SDValue prepareTS1AM(SDValue Op, SelectionDAG &DAG, SDValue &Flag,
SDValue &Bits) {
SDLoc DL(Op);
AtomicSDNode *N = cast<AtomicSDNode>(Op);
SDValue Ptr = N->getOperand(1);
SDValue Val = N->getOperand(2);
EVT PtrVT = Ptr.getValueType();
bool Byte = N->getMemoryVT() == MVT::i8;
SDValue Const3 = DAG.getConstant(3, DL, PtrVT);
SDValue Remainder = DAG.getNode(ISD::AND, DL, PtrVT, {Ptr, Const3});
SDValue Mask = Byte ? DAG.getConstant(1, DL, MVT::i32)
: DAG.getConstant(3, DL, MVT::i32);
Flag = DAG.getNode(ISD::SHL, DL, MVT::i32, {Mask, Remainder});
Bits = DAG.getNode(ISD::SHL, DL, PtrVT, {Remainder, Const3});
return DAG.getNode(ISD::SHL, DL, Val.getValueType(), {Val, Bits});
}
static SDValue finalizeTS1AM(SDValue Op, SelectionDAG &DAG, SDValue Data,
SDValue Bits) {
SDLoc DL(Op);
EVT VT = Data.getValueType();
bool Byte = cast<AtomicSDNode>(Op)->getMemoryVT() == MVT::i8;
SDValue NewData = DAG.getNode(ISD::SRL, DL, VT, Data, Bits);
return DAG.getNode(ISD::AND, DL, VT,
{NewData, DAG.getConstant(Byte ? 0xff : 0xffff, DL, VT)});
}
SDValue VETargetLowering::lowerATOMIC_SWAP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
AtomicSDNode *N = cast<AtomicSDNode>(Op);
if (N->getMemoryVT() == MVT::i8) {
SDValue Flag;
SDValue Bits;
SDValue NewVal = prepareTS1AM(Op, DAG, Flag, Bits);
SDValue Ptr = N->getOperand(1);
SDValue Aligned = DAG.getNode(ISD::AND, DL, Ptr.getValueType(),
{Ptr, DAG.getConstant(-4, DL, MVT::i64)});
SDValue TS1AM = DAG.getAtomic(VEISD::TS1AM, DL, N->getMemoryVT(),
DAG.getVTList(Op.getNode()->getValueType(0),
Op.getNode()->getValueType(1)),
{N->getChain(), Aligned, Flag, NewVal},
N->getMemOperand());
SDValue Result = finalizeTS1AM(Op, DAG, TS1AM, Bits);
SDValue Chain = TS1AM.getValue(1);
return DAG.getMergeValues({Result, Chain}, DL);
}
if (N->getMemoryVT() == MVT::i16) {
SDValue Flag;
SDValue Bits;
SDValue NewVal = prepareTS1AM(Op, DAG, Flag, Bits);
SDValue Ptr = N->getOperand(1);
SDValue Aligned = DAG.getNode(ISD::AND, DL, Ptr.getValueType(),
{Ptr, DAG.getConstant(-4, DL, MVT::i64)});
SDValue TS1AM = DAG.getAtomic(VEISD::TS1AM, DL, N->getMemoryVT(),
DAG.getVTList(Op.getNode()->getValueType(0),
Op.getNode()->getValueType(1)),
{N->getChain(), Aligned, Flag, NewVal},
N->getMemOperand());
SDValue Result = finalizeTS1AM(Op, DAG, TS1AM, Bits);
SDValue Chain = TS1AM.getValue(1);
return DAG.getMergeValues({Result, Chain}, DL);
}
return Op;
}
SDValue VETargetLowering::lowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const {
return makeAddress(Op, DAG);
}
SDValue VETargetLowering::lowerBlockAddress(SDValue Op,
SelectionDAG &DAG) const {
return makeAddress(Op, DAG);
}
SDValue VETargetLowering::lowerConstantPool(SDValue Op,
SelectionDAG &DAG) const {
return makeAddress(Op, DAG);
}
SDValue
VETargetLowering::lowerToTLSGeneralDynamicModel(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
SDValue Label = withTargetFlags(Op, 0, DAG);
EVT PtrVT = Op.getValueType();
SDValue Chain = DAG.getEntryNode();
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
const uint32_t *Mask = Subtarget->getRegisterInfo()->getCallPreservedMask(
DAG.getMachineFunction(), CallingConv::C);
Chain = DAG.getCALLSEQ_START(Chain, 64, 0, DL);
SDValue Args[] = {Chain, Label, DAG.getRegisterMask(Mask), Chain.getValue(1)};
Chain = DAG.getNode(VEISD::GETTLSADDR, DL, NodeTys, Args);
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(64, DL, true),
DAG.getIntPtrConstant(0, DL, true),
Chain.getValue(1), DL);
Chain = DAG.getCopyFromReg(Chain, DL, VE::SX0, PtrVT, Chain.getValue(1));
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
MFI.setHasCalls(true);
if (isPositionIndependent()) {
MachineFunction &MF = DAG.getMachineFunction();
Subtarget->getInstrInfo()->getGlobalBaseReg(&MF);
}
return Chain;
}
SDValue VETargetLowering::lowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
return lowerToTLSGeneralDynamicModel(Op, DAG);
}
SDValue VETargetLowering::lowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
return makeAddress(Op, DAG);
}
static SDValue lowerLoadF128(SDValue Op, SelectionDAG &DAG) {
SDLoc DL(Op);
LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode());
assert(LdNode && LdNode->getOffset().isUndef() && "Unexpected node type");
unsigned Alignment = LdNode->getAlign().value();
if (Alignment > 8)
Alignment = 8;
SDValue Lo64 =
DAG.getLoad(MVT::f64, DL, LdNode->getChain(), LdNode->getBasePtr(),
LdNode->getPointerInfo(), Alignment,
LdNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
EVT AddrVT = LdNode->getBasePtr().getValueType();
SDValue HiPtr = DAG.getNode(ISD::ADD, DL, AddrVT, LdNode->getBasePtr(),
DAG.getConstant(8, DL, AddrVT));
SDValue Hi64 =
DAG.getLoad(MVT::f64, DL, LdNode->getChain(), HiPtr,
LdNode->getPointerInfo(), Alignment,
LdNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
SDValue SubRegEven = DAG.getTargetConstant(VE::sub_even, DL, MVT::i32);
SDValue SubRegOdd = DAG.getTargetConstant(VE::sub_odd, DL, MVT::i32);
SDNode *InFP128 =
DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::f128);
InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL, MVT::f128,
SDValue(InFP128, 0), Hi64, SubRegEven);
InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, DL, MVT::f128,
SDValue(InFP128, 0), Lo64, SubRegOdd);
SDValue OutChains[2] = {SDValue(Lo64.getNode(), 1),
SDValue(Hi64.getNode(), 1)};
SDValue OutChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
SDValue Ops[2] = {SDValue(InFP128, 0), OutChain};
return DAG.getMergeValues(Ops, DL);
}
static SDValue lowerLoadI1(SDValue Op, SelectionDAG &DAG) {
SDLoc DL(Op);
LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode());
assert(LdNode && LdNode->getOffset().isUndef() && "Unexpected node type");
SDValue BasePtr = LdNode->getBasePtr();
unsigned Alignment = LdNode->getAlign().value();
if (Alignment > 8)
Alignment = 8;
EVT AddrVT = BasePtr.getValueType();
EVT MemVT = LdNode->getMemoryVT();
if (MemVT == MVT::v256i1 || MemVT == MVT::v4i64) {
SDValue OutChains[4];
SDNode *VM = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MemVT);
for (int i = 0; i < 4; ++i) {
SDValue Addr = DAG.getNode(ISD::ADD, DL, AddrVT, BasePtr,
DAG.getConstant(8 * i, DL, AddrVT));
SDValue Val =
DAG.getLoad(MVT::i64, DL, LdNode->getChain(), Addr,
LdNode->getPointerInfo(), Alignment,
LdNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
OutChains[i] = SDValue(Val.getNode(), 1);
VM = DAG.getMachineNode(VE::LVMir_m, DL, MVT::i64,
DAG.getTargetConstant(i, DL, MVT::i64), Val,
SDValue(VM, 0));
}
SDValue OutChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
SDValue Ops[2] = {SDValue(VM, 0), OutChain};
return DAG.getMergeValues(Ops, DL);
} else if (MemVT == MVT::v512i1 || MemVT == MVT::v8i64) {
SDValue OutChains[8];
SDNode *VM = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MemVT);
for (int i = 0; i < 8; ++i) {
SDValue Addr = DAG.getNode(ISD::ADD, DL, AddrVT, BasePtr,
DAG.getConstant(8 * i, DL, AddrVT));
SDValue Val =
DAG.getLoad(MVT::i64, DL, LdNode->getChain(), Addr,
LdNode->getPointerInfo(), Alignment,
LdNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
OutChains[i] = SDValue(Val.getNode(), 1);
VM = DAG.getMachineNode(VE::LVMyir_y, DL, MVT::i64,
DAG.getTargetConstant(i, DL, MVT::i64), Val,
SDValue(VM, 0));
}
SDValue OutChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
SDValue Ops[2] = {SDValue(VM, 0), OutChain};
return DAG.getMergeValues(Ops, DL);
} else {
return SDValue();
}
}
SDValue VETargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const {
LoadSDNode *LdNode = cast<LoadSDNode>(Op.getNode());
EVT MemVT = LdNode->getMemoryVT();
if (MemVT.isVector() && !isMaskType(MemVT))
return lowerToVVP(Op, DAG);
SDValue BasePtr = LdNode->getBasePtr();
if (isa<FrameIndexSDNode>(BasePtr.getNode())) {
return Op;
}
if (MemVT == MVT::f128)
return lowerLoadF128(Op, DAG);
if (isMaskType(MemVT))
return lowerLoadI1(Op, DAG);
return Op;
}
static SDValue lowerStoreF128(SDValue Op, SelectionDAG &DAG) {
SDLoc DL(Op);
StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode());
assert(StNode && StNode->getOffset().isUndef() && "Unexpected node type");
SDValue SubRegEven = DAG.getTargetConstant(VE::sub_even, DL, MVT::i32);
SDValue SubRegOdd = DAG.getTargetConstant(VE::sub_odd, DL, MVT::i32);
SDNode *Hi64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, MVT::i64,
StNode->getValue(), SubRegEven);
SDNode *Lo64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, MVT::i64,
StNode->getValue(), SubRegOdd);
unsigned Alignment = StNode->getAlign().value();
if (Alignment > 8)
Alignment = 8;
SDValue OutChains[2];
OutChains[0] =
DAG.getStore(StNode->getChain(), DL, SDValue(Lo64, 0),
StNode->getBasePtr(), MachinePointerInfo(), Alignment,
StNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
EVT AddrVT = StNode->getBasePtr().getValueType();
SDValue HiPtr = DAG.getNode(ISD::ADD, DL, AddrVT, StNode->getBasePtr(),
DAG.getConstant(8, DL, AddrVT));
OutChains[1] =
DAG.getStore(StNode->getChain(), DL, SDValue(Hi64, 0), HiPtr,
MachinePointerInfo(), Alignment,
StNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
}
static SDValue lowerStoreI1(SDValue Op, SelectionDAG &DAG) {
SDLoc DL(Op);
StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode());
assert(StNode && StNode->getOffset().isUndef() && "Unexpected node type");
SDValue BasePtr = StNode->getBasePtr();
unsigned Alignment = StNode->getAlign().value();
if (Alignment > 8)
Alignment = 8;
EVT AddrVT = BasePtr.getValueType();
EVT MemVT = StNode->getMemoryVT();
if (MemVT == MVT::v256i1 || MemVT == MVT::v4i64) {
SDValue OutChains[4];
for (int i = 0; i < 4; ++i) {
SDNode *V =
DAG.getMachineNode(VE::SVMmi, DL, MVT::i64, StNode->getValue(),
DAG.getTargetConstant(i, DL, MVT::i64));
SDValue Addr = DAG.getNode(ISD::ADD, DL, AddrVT, BasePtr,
DAG.getConstant(8 * i, DL, AddrVT));
OutChains[i] =
DAG.getStore(StNode->getChain(), DL, SDValue(V, 0), Addr,
MachinePointerInfo(), Alignment,
StNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
}
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
} else if (MemVT == MVT::v512i1 || MemVT == MVT::v8i64) {
SDValue OutChains[8];
for (int i = 0; i < 8; ++i) {
SDNode *V =
DAG.getMachineNode(VE::SVMyi, DL, MVT::i64, StNode->getValue(),
DAG.getTargetConstant(i, DL, MVT::i64));
SDValue Addr = DAG.getNode(ISD::ADD, DL, AddrVT, BasePtr,
DAG.getConstant(8 * i, DL, AddrVT));
OutChains[i] =
DAG.getStore(StNode->getChain(), DL, SDValue(V, 0), Addr,
MachinePointerInfo(), Alignment,
StNode->isVolatile() ? MachineMemOperand::MOVolatile
: MachineMemOperand::MONone);
}
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
} else {
return SDValue();
}
}
SDValue VETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const {
StoreSDNode *StNode = cast<StoreSDNode>(Op.getNode());
assert(StNode && StNode->getOffset().isUndef() && "Unexpected node type");
EVT MemVT = StNode->getMemoryVT();
if (MemVT.isVector() && !isMaskType(MemVT))
return lowerToVVP(Op, DAG);
SDValue BasePtr = StNode->getBasePtr();
if (isa<FrameIndexSDNode>(BasePtr.getNode())) {
return Op;
}
if (MemVT == MVT::f128)
return lowerStoreF128(Op, DAG);
if (isMaskType(MemVT))
return lowerStoreI1(Op, DAG);
return SDValue();
}
SDValue VETargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
VEMachineFunctionInfo *FuncInfo = MF.getInfo<VEMachineFunctionInfo>();
auto PtrVT = getPointerTy(DAG.getDataLayout());
MF.getFrameInfo().setFrameAddressIsTaken(true);
SDLoc DL(Op);
SDValue Offset =
DAG.getNode(ISD::ADD, DL, PtrVT, DAG.getRegister(VE::SX9, PtrVT),
DAG.getIntPtrConstant(FuncInfo->getVarArgsFrameOffset(), DL));
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
return DAG.getStore(Op.getOperand(0), DL, Offset, Op.getOperand(1),
MachinePointerInfo(SV));
}
SDValue VETargetLowering::lowerVAARG(SDValue Op, SelectionDAG &DAG) const {
SDNode *Node = Op.getNode();
EVT VT = Node->getValueType(0);
SDValue InChain = Node->getOperand(0);
SDValue VAListPtr = Node->getOperand(1);
EVT PtrVT = VAListPtr.getValueType();
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
SDLoc DL(Node);
SDValue VAList =
DAG.getLoad(PtrVT, DL, InChain, VAListPtr, MachinePointerInfo(SV));
SDValue Chain = VAList.getValue(1);
SDValue NextPtr;
if (VT == MVT::f128) {
int Align = 16;
VAList = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
DAG.getConstant(Align - 1, DL, PtrVT));
VAList = DAG.getNode(ISD::AND, DL, PtrVT, VAList,
DAG.getConstant(-Align, DL, PtrVT));
NextPtr =
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getIntPtrConstant(16, DL));
} else if (VT == MVT::f32) {
NextPtr =
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getIntPtrConstant(8, DL));
unsigned InternalOffset = 4;
VAList = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
DAG.getConstant(InternalOffset, DL, PtrVT));
} else {
NextPtr =
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getIntPtrConstant(8, DL));
}
InChain = DAG.getStore(Chain, DL, NextPtr, VAListPtr, MachinePointerInfo(SV));
return DAG.getLoad(VT, DL, InChain, VAList, MachinePointerInfo(),
std::min(PtrVT.getSizeInBits(), VT.getSizeInBits()) / 8);
}
SDValue VETargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
SDNode *Node = Op.getNode();
SDValue Chain = Op.getOperand(0);
SDValue Size = Op.getOperand(1);
MaybeAlign Alignment(Op.getConstantOperandVal(2));
EVT VT = Node->getValueType(0);
Chain = DAG.getCALLSEQ_START(Chain, 0, 0, DL);
const TargetFrameLowering &TFI = *Subtarget->getFrameLowering();
Align StackAlign = TFI.getStackAlign();
bool NeedsAlign = Alignment.valueOrOne() > StackAlign;
TargetLowering::ArgListTy Args;
TargetLowering::ArgListEntry Entry;
Entry.Node = Size;
Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext());
Args.push_back(Entry);
if (NeedsAlign) {
Entry.Node = DAG.getConstant(~(Alignment->value() - 1ULL), DL, VT);
Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext());
Args.push_back(Entry);
}
Type *RetTy = Type::getVoidTy(*DAG.getContext());
EVT PtrVT = Op.getValueType();
SDValue Callee;
if (NeedsAlign) {
Callee = DAG.getTargetExternalSymbol("__ve_grow_stack_align", PtrVT, 0);
} else {
Callee = DAG.getTargetExternalSymbol("__ve_grow_stack", PtrVT, 0);
}
TargetLowering::CallLoweringInfo CLI(DAG);
CLI.setDebugLoc(DL)
.setChain(Chain)
.setCallee(CallingConv::PreserveAll, RetTy, Callee, std::move(Args))
.setDiscardResult(true);
std::pair<SDValue, SDValue> pair = LowerCallTo(CLI);
Chain = pair.second;
SDValue Result = DAG.getNode(VEISD::GETSTACKTOP, DL, VT, Chain);
if (NeedsAlign) {
Result = DAG.getNode(ISD::ADD, DL, VT, Result,
DAG.getConstant((Alignment->value() - 1ULL), DL, VT));
Result = DAG.getNode(ISD::AND, DL, VT, Result,
DAG.getConstant(~(Alignment->value() - 1ULL), DL, VT));
}
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(0, DL, true),
DAG.getIntPtrConstant(0, DL, true), SDValue(), DL);
SDValue Ops[2] = {Result, Chain};
return DAG.getMergeValues(Ops, DL);
}
SDValue VETargetLowering::lowerEH_SJLJ_LONGJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
return DAG.getNode(VEISD::EH_SJLJ_LONGJMP, DL, MVT::Other, Op.getOperand(0),
Op.getOperand(1));
}
SDValue VETargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
return DAG.getNode(VEISD::EH_SJLJ_SETJMP, DL,
DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0),
Op.getOperand(1));
}
SDValue VETargetLowering::lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
return DAG.getNode(VEISD::EH_SJLJ_SETUP_DISPATCH, DL, MVT::Other,
Op.getOperand(0));
}
static SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG,
const VETargetLowering &TLI,
const VESubtarget *Subtarget) {
SDLoc DL(Op);
MachineFunction &MF = DAG.getMachineFunction();
EVT PtrVT = TLI.getPointerTy(MF.getDataLayout());
MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.setFrameAddressIsTaken(true);
unsigned Depth = Op.getConstantOperandVal(0);
const VERegisterInfo *RegInfo = Subtarget->getRegisterInfo();
Register FrameReg = RegInfo->getFrameRegister(MF);
SDValue FrameAddr =
DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, PtrVT);
while (Depth--)
FrameAddr = DAG.getLoad(Op.getValueType(), DL, DAG.getEntryNode(),
FrameAddr, MachinePointerInfo());
return FrameAddr;
}
static SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG,
const VETargetLowering &TLI,
const VESubtarget *Subtarget) {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.setReturnAddressIsTaken(true);
if (TLI.verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
SDValue FrameAddr = lowerFRAMEADDR(Op, DAG, TLI, Subtarget);
SDLoc DL(Op);
EVT VT = Op.getValueType();
SDValue Offset = DAG.getConstant(8, DL, VT);
return DAG.getLoad(VT, DL, DAG.getEntryNode(),
DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset),
MachinePointerInfo());
}
SDValue VETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
switch (IntNo) {
default: return SDValue();
case Intrinsic::eh_sjlj_lsda: {
MachineFunction &MF = DAG.getMachineFunction();
MVT VT = Op.getSimpleValueType();
const VETargetMachine *TM =
static_cast<const VETargetMachine *>(&DAG.getTarget());
TM->getStrList()->push_back(std::string(
(Twine("GCC_except_table") + Twine(MF.getFunctionNumber())).str()));
SDValue Addr =
DAG.getTargetExternalSymbol(TM->getStrList()->back().c_str(), VT, 0);
if (isPositionIndependent()) {
Addr = makeHiLoPair(Addr, VEMCExpr::VK_VE_GOTOFF_HI32,
VEMCExpr::VK_VE_GOTOFF_LO32, DAG);
SDValue GlobalBase = DAG.getNode(VEISD::GLOBAL_BASE_REG, DL, VT);
return DAG.getNode(ISD::ADD, DL, VT, GlobalBase, Addr);
}
return makeHiLoPair(Addr, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
}
}
}
static bool getUniqueInsertion(SDNode *N, unsigned &UniqueIdx) {
if (!isa<BuildVectorSDNode>(N))
return false;
const auto *BVN = cast<BuildVectorSDNode>(N);
unsigned Idx;
for (Idx = 0; Idx < BVN->getNumOperands(); ++Idx) {
auto ElemV = BVN->getOperand(Idx);
if (!ElemV->isUndef())
break;
}
if (Idx == BVN->getNumOperands())
return false;
UniqueIdx = Idx++;
for (; Idx < BVN->getNumOperands(); ++Idx) {
auto ElemV = BVN->getOperand(Idx);
if (!ElemV->isUndef())
return false;
}
return true;
}
static SDValue getSplatValue(SDNode *N) {
if (auto *BuildVec = dyn_cast<BuildVectorSDNode>(N)) {
return BuildVec->getSplatValue();
}
return SDValue();
}
SDValue VETargetLowering::lowerBUILD_VECTOR(SDValue Op,
SelectionDAG &DAG) const {
VECustomDAG CDAG(DAG, Op);
MVT ResultVT = Op.getSimpleValueType();
unsigned UniqueIdx;
if (getUniqueInsertion(Op.getNode(), UniqueIdx)) {
SDValue AccuV = CDAG.getUNDEF(Op.getValueType());
auto ElemV = Op->getOperand(UniqueIdx);
SDValue IdxV = CDAG.getConstant(UniqueIdx, MVT::i64);
return CDAG.getNode(ISD::INSERT_VECTOR_ELT, ResultVT, {AccuV, ElemV, IdxV});
}
if (SDValue ScalarV = getSplatValue(Op.getNode())) {
unsigned NumEls = ResultVT.getVectorNumElements();
auto AVL = CDAG.getConstant(NumEls, MVT::i32);
return CDAG.getBroadcast(ResultVT, ScalarV, AVL);
}
return SDValue();
}
TargetLowering::LegalizeAction
VETargetLowering::getCustomOperationAction(SDNode &Op) const {
if (isPackingSupportOpcode(Op.getOpcode()))
return Legal;
if (isVVPOrVEC(Op.getOpcode()))
return Custom;
return Legal;
}
SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
LLVM_DEBUG(dbgs() << "::LowerOperation"; Op->print(dbgs()););
unsigned Opcode = Op.getOpcode();
switch (Opcode) {
case ISD::ATOMIC_FENCE:
return lowerATOMIC_FENCE(Op, DAG);
case ISD::ATOMIC_SWAP:
return lowerATOMIC_SWAP(Op, DAG);
case ISD::BlockAddress:
return lowerBlockAddress(Op, DAG);
case ISD::ConstantPool:
return lowerConstantPool(Op, DAG);
case ISD::DYNAMIC_STACKALLOC:
return lowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::EH_SJLJ_LONGJMP:
return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETJMP:
return lowerEH_SJLJ_SETJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH:
return lowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
case ISD::FRAMEADDR:
return lowerFRAMEADDR(Op, DAG, *this, Subtarget);
case ISD::GlobalAddress:
return lowerGlobalAddress(Op, DAG);
case ISD::GlobalTLSAddress:
return lowerGlobalTLSAddress(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN:
return lowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::JumpTable:
return lowerJumpTable(Op, DAG);
case ISD::LOAD:
return lowerLOAD(Op, DAG);
case ISD::RETURNADDR:
return lowerRETURNADDR(Op, DAG, *this, Subtarget);
case ISD::BUILD_VECTOR:
return lowerBUILD_VECTOR(Op, DAG);
case ISD::STORE:
return lowerSTORE(Op, DAG);
case ISD::VASTART:
return lowerVASTART(Op, DAG);
case ISD::VAARG:
return lowerVAARG(Op, DAG);
case ISD::INSERT_VECTOR_ELT:
return lowerINSERT_VECTOR_ELT(Op, DAG);
case ISD::EXTRACT_VECTOR_ELT:
return lowerEXTRACT_VECTOR_ELT(Op, DAG);
}
LLVM_DEBUG(dbgs() << "::LowerOperation_VVP"; Op->print(dbgs()););
if (ISD::isVPOpcode(Opcode))
return lowerToVVP(Op, DAG);
switch (Opcode) {
default:
llvm_unreachable("Should not custom lower this!");
case VEISD::VEC_BROADCAST:
#define ADD_VVP_OP(VVP_NAME, ...) case VEISD::VVP_NAME:
#include "VVPNodes.def"
if (getAnnotatedNodeAVL(Op).second)
return Op;
return legalizeInternalVectorOp(Op, DAG);
case ISD::MLOAD:
case ISD::MSTORE:
#define ADD_VVP_OP(VVP_NAME, ISD_NAME) case ISD::ISD_NAME:
#include "VVPNodes.def"
if (isMaskArithmetic(Op) && isPackedVectorType(Op.getValueType()))
return splitMaskArithmetic(Op, DAG);
return lowerToVVP(Op, DAG);
}
}
void VETargetLowering::ReplaceNodeResults(SDNode *N,
SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const {
switch (N->getOpcode()) {
case ISD::ATOMIC_SWAP:
return;
default:
LLVM_DEBUG(N->dumpr(&DAG));
llvm_unreachable("Do not know how to custom type legalize this operation!");
}
}
unsigned VETargetLowering::getJumpTableEncoding() const {
if (isPositionIndependent())
return MachineJumpTableInfo::EK_Custom32;
return TargetLowering::getJumpTableEncoding();
}
const MCExpr *VETargetLowering::LowerCustomJumpTableEntry(
const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB,
unsigned Uid, MCContext &Ctx) const {
assert(isPositionIndependent());
const auto *Value = MCSymbolRefExpr::create(MBB->getSymbol(), Ctx);
MCSymbol *Sym = Ctx.getOrCreateSymbol(MBB->getParent()->getName().data());
const auto *Base = MCSymbolRefExpr::create(Sym, Ctx);
return MCBinaryExpr::createSub(Value, Base, Ctx);
}
SDValue VETargetLowering::getPICJumpTableRelocBase(SDValue Table,
SelectionDAG &DAG) const {
assert(isPositionIndependent());
SDLoc DL(Table);
Function *Function = &DAG.getMachineFunction().getFunction();
assert(Function != nullptr);
auto PtrTy = getPointerTy(DAG.getDataLayout(), Function->getAddressSpace());
SDValue Op = DAG.getGlobalAddress(Function, DL, PtrTy);
SDValue HiLo = makeHiLoPair(Op, VEMCExpr::VK_VE_GOTOFF_HI32,
VEMCExpr::VK_VE_GOTOFF_LO32, DAG);
SDValue GlobalBase = DAG.getNode(VEISD::GLOBAL_BASE_REG, DL, PtrTy);
return DAG.getNode(ISD::ADD, DL, PtrTy, GlobalBase, HiLo);
}
Register VETargetLowering::prepareMBB(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
MachineBasicBlock *TargetBB,
const DebugLoc &DL) const {
MachineFunction *MF = MBB.getParent();
MachineRegisterInfo &MRI = MF->getRegInfo();
const VEInstrInfo *TII = Subtarget->getInstrInfo();
const TargetRegisterClass *RC = &VE::I64RegClass;
Register Tmp1 = MRI.createVirtualRegister(RC);
Register Tmp2 = MRI.createVirtualRegister(RC);
Register Result = MRI.createVirtualRegister(RC);
if (isPositionIndependent()) {
BuildMI(MBB, I, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addMBB(TargetBB, VEMCExpr::VK_VE_GOTOFF_LO32);
BuildMI(MBB, I, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(MBB, I, DL, TII->get(VE::LEASLrri), Result)
.addReg(VE::SX15)
.addReg(Tmp2, getKillRegState(true))
.addMBB(TargetBB, VEMCExpr::VK_VE_GOTOFF_HI32);
} else {
BuildMI(MBB, I, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addMBB(TargetBB, VEMCExpr::VK_VE_LO32);
BuildMI(MBB, I, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(MBB, I, DL, TII->get(VE::LEASLrii), Result)
.addReg(Tmp2, getKillRegState(true))
.addImm(0)
.addMBB(TargetBB, VEMCExpr::VK_VE_HI32);
}
return Result;
}
Register VETargetLowering::prepareSymbol(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
StringRef Symbol, const DebugLoc &DL,
bool IsLocal = false,
bool IsCall = false) const {
MachineFunction *MF = MBB.getParent();
MachineRegisterInfo &MRI = MF->getRegInfo();
const VEInstrInfo *TII = Subtarget->getInstrInfo();
const TargetRegisterClass *RC = &VE::I64RegClass;
Register Result = MRI.createVirtualRegister(RC);
if (isPositionIndependent()) {
if (IsCall && !IsLocal) {
BuildMI(MBB, I, DL, TII->get(VE::GETFUNPLT), Result)
.addExternalSymbol("abort");
} else if (IsLocal) {
Register Tmp1 = MRI.createVirtualRegister(RC);
Register Tmp2 = MRI.createVirtualRegister(RC);
BuildMI(MBB, I, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addExternalSymbol(Symbol.data(), VEMCExpr::VK_VE_GOTOFF_LO32);
BuildMI(MBB, I, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(MBB, I, DL, TII->get(VE::LEASLrri), Result)
.addReg(VE::SX15)
.addReg(Tmp2, getKillRegState(true))
.addExternalSymbol(Symbol.data(), VEMCExpr::VK_VE_GOTOFF_HI32);
} else {
Register Tmp1 = MRI.createVirtualRegister(RC);
Register Tmp2 = MRI.createVirtualRegister(RC);
Register Tmp3 = MRI.createVirtualRegister(RC);
BuildMI(MBB, I, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addExternalSymbol(Symbol.data(), VEMCExpr::VK_VE_GOT_LO32);
BuildMI(MBB, I, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(MBB, I, DL, TII->get(VE::LEASLrri), Tmp3)
.addReg(VE::SX15)
.addReg(Tmp2, getKillRegState(true))
.addExternalSymbol(Symbol.data(), VEMCExpr::VK_VE_GOT_HI32);
BuildMI(MBB, I, DL, TII->get(VE::LDrii), Result)
.addReg(Tmp3, getKillRegState(true))
.addImm(0)
.addImm(0);
}
} else {
Register Tmp1 = MRI.createVirtualRegister(RC);
Register Tmp2 = MRI.createVirtualRegister(RC);
BuildMI(MBB, I, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addExternalSymbol(Symbol.data(), VEMCExpr::VK_VE_LO32);
BuildMI(MBB, I, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(MBB, I, DL, TII->get(VE::LEASLrii), Result)
.addReg(Tmp2, getKillRegState(true))
.addImm(0)
.addExternalSymbol(Symbol.data(), VEMCExpr::VK_VE_HI32);
}
return Result;
}
void VETargetLowering::setupEntryBlockForSjLj(MachineInstr &MI,
MachineBasicBlock *MBB,
MachineBasicBlock *DispatchBB,
int FI, int Offset) const {
DebugLoc DL = MI.getDebugLoc();
const VEInstrInfo *TII = Subtarget->getInstrInfo();
Register LabelReg =
prepareMBB(*MBB, MachineBasicBlock::iterator(MI), DispatchBB, DL);
MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
addFrameReference(MIB, FI, Offset); MIB.addReg(LabelReg, getKillRegState(true));
}
MachineBasicBlock *
VETargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
DebugLoc DL = MI.getDebugLoc();
MachineFunction *MF = MBB->getParent();
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
MachineRegisterInfo &MRI = MF->getRegInfo();
const BasicBlock *BB = MBB->getBasicBlock();
MachineFunction::iterator I = ++MBB->getIterator();
SmallVector<MachineMemOperand *, 2> MMOs(MI.memoperands_begin(),
MI.memoperands_end());
Register BufReg = MI.getOperand(1).getReg();
Register DstReg;
DstReg = MI.getOperand(0).getReg();
const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
(void)TRI;
Register MainDestReg = MRI.createVirtualRegister(RC);
Register RestoreDestReg = MRI.createVirtualRegister(RC);
MachineBasicBlock *ThisMBB = MBB;
MachineBasicBlock *MainMBB = MF->CreateMachineBasicBlock(BB);
MachineBasicBlock *SinkMBB = MF->CreateMachineBasicBlock(BB);
MachineBasicBlock *RestoreMBB = MF->CreateMachineBasicBlock(BB);
MF->insert(I, MainMBB);
MF->insert(I, SinkMBB);
MF->push_back(RestoreMBB);
RestoreMBB->setHasAddressTaken();
SinkMBB->splice(SinkMBB->begin(), MBB,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
Register LabelReg =
prepareMBB(*MBB, MachineBasicBlock::iterator(MI), RestoreMBB, DL);
const VEFrameLowering *TFI = Subtarget->getFrameLowering();
if (TFI->hasBP(*MF)) {
MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
MIB.addReg(BufReg);
MIB.addImm(0);
MIB.addImm(24);
MIB.addReg(VE::SX17);
MIB.setMemRefs(MMOs);
}
MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
MIB.add(MI.getOperand(1)); MIB.addImm(0);
MIB.addImm(8);
MIB.addReg(LabelReg, getKillRegState(true));
MIB.setMemRefs(MMOs);
MIB =
BuildMI(*ThisMBB, MI, DL, TII->get(VE::EH_SjLj_Setup)).addMBB(RestoreMBB);
const VERegisterInfo *RegInfo = Subtarget->getRegisterInfo();
MIB.addRegMask(RegInfo->getNoPreservedMask());
ThisMBB->addSuccessor(MainMBB);
ThisMBB->addSuccessor(RestoreMBB);
BuildMI(MainMBB, DL, TII->get(VE::LEAzii), MainDestReg)
.addImm(0)
.addImm(0)
.addImm(0);
MainMBB->addSuccessor(SinkMBB);
BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII->get(VE::PHI), DstReg)
.addReg(MainDestReg)
.addMBB(MainMBB)
.addReg(RestoreDestReg)
.addMBB(RestoreMBB);
if (TFI->hasBP(*MF)) {
MachineInstrBuilder MIB =
BuildMI(RestoreMBB, DL, TII->get(VE::LDrii), VE::SX17);
MIB.addReg(VE::SX10);
MIB.addImm(0);
MIB.addImm(24);
MIB.setMemRefs(MMOs);
}
BuildMI(RestoreMBB, DL, TII->get(VE::LEAzii), RestoreDestReg)
.addImm(0)
.addImm(0)
.addImm(1);
BuildMI(RestoreMBB, DL, TII->get(VE::BRCFLa_t)).addMBB(SinkMBB);
RestoreMBB->addSuccessor(SinkMBB);
MI.eraseFromParent();
return SinkMBB;
}
MachineBasicBlock *
VETargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
DebugLoc DL = MI.getDebugLoc();
MachineFunction *MF = MBB->getParent();
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
MachineRegisterInfo &MRI = MF->getRegInfo();
SmallVector<MachineMemOperand *, 2> MMOs(MI.memoperands_begin(),
MI.memoperands_end());
Register BufReg = MI.getOperand(0).getReg();
Register Tmp = MRI.createVirtualRegister(&VE::I64RegClass);
Register FP = VE::SX9;
Register SP = VE::SX11;
MachineInstrBuilder MIB;
MachineBasicBlock *ThisMBB = MBB;
MIB = BuildMI(*ThisMBB, MI, DL, TII->get(VE::LDrii), FP);
MIB.addReg(BufReg);
MIB.addImm(0);
MIB.addImm(0);
MIB.setMemRefs(MMOs);
MIB = BuildMI(*ThisMBB, MI, DL, TII->get(VE::LDrii), Tmp);
MIB.addReg(BufReg);
MIB.addImm(0);
MIB.addImm(8);
MIB.setMemRefs(MMOs);
BuildMI(*ThisMBB, MI, DL, TII->get(VE::ORri), VE::SX10)
.addReg(BufReg)
.addImm(0);
MIB = BuildMI(*ThisMBB, MI, DL, TII->get(VE::LDrii), SP);
MIB.add(MI.getOperand(0)); MIB.addImm(0);
MIB.addImm(16);
MIB.setMemRefs(MMOs);
BuildMI(*ThisMBB, MI, DL, TII->get(VE::BCFLari_t))
.addReg(Tmp, getKillRegState(true))
.addImm(0);
MI.eraseFromParent();
return ThisMBB;
}
MachineBasicBlock *
VETargetLowering::emitSjLjDispatchBlock(MachineInstr &MI,
MachineBasicBlock *BB) const {
DebugLoc DL = MI.getDebugLoc();
MachineFunction *MF = BB->getParent();
MachineFrameInfo &MFI = MF->getFrameInfo();
MachineRegisterInfo &MRI = MF->getRegInfo();
const VEInstrInfo *TII = Subtarget->getInstrInfo();
int FI = MFI.getFunctionContextIndex();
DenseMap<unsigned, SmallVector<MachineBasicBlock *, 2>> CallSiteNumToLPad;
unsigned MaxCSNum = 0;
for (auto &MBB : *MF) {
if (!MBB.isEHPad())
continue;
MCSymbol *Sym = nullptr;
for (const auto &MI : MBB) {
if (MI.isDebugInstr())
continue;
assert(MI.isEHLabel() && "expected EH_LABEL");
Sym = MI.getOperand(0).getMCSymbol();
break;
}
if (!MF->hasCallSiteLandingPad(Sym))
continue;
for (unsigned CSI : MF->getCallSiteLandingPad(Sym)) {
CallSiteNumToLPad[CSI].push_back(&MBB);
MaxCSNum = std::max(MaxCSNum, CSI);
}
}
std::vector<MachineBasicBlock *> LPadList;
SmallPtrSet<MachineBasicBlock *, 32> InvokeBBs;
LPadList.reserve(CallSiteNumToLPad.size());
for (unsigned CSI = 1; CSI <= MaxCSNum; ++CSI) {
for (auto &LP : CallSiteNumToLPad[CSI]) {
LPadList.push_back(LP);
InvokeBBs.insert(LP->pred_begin(), LP->pred_end());
}
}
assert(!LPadList.empty() &&
"No landing pad destinations for the dispatch jump table!");
static const int OffsetIC = 72;
static const int OffsetCS = 8;
MachineBasicBlock *DispatchBB = MF->CreateMachineBasicBlock();
DispatchBB->setIsEHPad(true);
MachineBasicBlock *TrapBB = MF->CreateMachineBasicBlock();
DispatchBB->addSuccessor(TrapBB);
MachineBasicBlock *DispContBB = MF->CreateMachineBasicBlock();
DispatchBB->addSuccessor(DispContBB);
MF->push_back(DispatchBB);
MF->push_back(DispContBB);
MF->push_back(TrapBB);
Register Abort = prepareSymbol(*TrapBB, TrapBB->end(), "abort", DL,
false, true);
BuildMI(TrapBB, DL, TII->get(VE::BSICrii), VE::SX10)
.addReg(Abort, getKillRegState(true))
.addImm(0)
.addImm(0);
setupEntryBlockForSjLj(MI, BB, DispatchBB, FI, OffsetIC);
unsigned JTE = getJumpTableEncoding();
MachineJumpTableInfo *JTI = MF->getOrCreateJumpTableInfo(JTE);
unsigned MJTI = JTI->createJumpTableIndex(LPadList);
const VERegisterInfo &RI = TII->getRegisterInfo();
BuildMI(DispatchBB, DL, TII->get(VE::NOP))
.addRegMask(RI.getNoPreservedMask());
if (isPositionIndependent()) {
BuildMI(DispatchBB, DL, TII->get(VE::GETGOT), VE::SX15);
}
const TargetRegisterClass *RC = &VE::I64RegClass;
Register IReg = MRI.createVirtualRegister(RC);
addFrameReference(BuildMI(DispatchBB, DL, TII->get(VE::LDLZXrii), IReg), FI,
OffsetCS);
if (LPadList.size() < 64) {
BuildMI(DispatchBB, DL, TII->get(VE::BRCFLir_t))
.addImm(VECC::CC_ILE)
.addImm(LPadList.size())
.addReg(IReg)
.addMBB(TrapBB);
} else {
assert(LPadList.size() <= 0x7FFFFFFF && "Too large Landing Pad!");
Register TmpReg = MRI.createVirtualRegister(RC);
BuildMI(DispatchBB, DL, TII->get(VE::LEAzii), TmpReg)
.addImm(0)
.addImm(0)
.addImm(LPadList.size());
BuildMI(DispatchBB, DL, TII->get(VE::BRCFLrr_t))
.addImm(VECC::CC_ILE)
.addReg(TmpReg, getKillRegState(true))
.addReg(IReg)
.addMBB(TrapBB);
}
Register BReg = MRI.createVirtualRegister(RC);
Register Tmp1 = MRI.createVirtualRegister(RC);
Register Tmp2 = MRI.createVirtualRegister(RC);
if (isPositionIndependent()) {
BuildMI(DispContBB, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addJumpTableIndex(MJTI, VEMCExpr::VK_VE_GOTOFF_LO32);
BuildMI(DispContBB, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(DispContBB, DL, TII->get(VE::LEASLrri), BReg)
.addReg(VE::SX15)
.addReg(Tmp2, getKillRegState(true))
.addJumpTableIndex(MJTI, VEMCExpr::VK_VE_GOTOFF_HI32);
} else {
BuildMI(DispContBB, DL, TII->get(VE::LEAzii), Tmp1)
.addImm(0)
.addImm(0)
.addJumpTableIndex(MJTI, VEMCExpr::VK_VE_LO32);
BuildMI(DispContBB, DL, TII->get(VE::ANDrm), Tmp2)
.addReg(Tmp1, getKillRegState(true))
.addImm(M0(32));
BuildMI(DispContBB, DL, TII->get(VE::LEASLrii), BReg)
.addReg(Tmp2, getKillRegState(true))
.addImm(0)
.addJumpTableIndex(MJTI, VEMCExpr::VK_VE_HI32);
}
switch (JTE) {
case MachineJumpTableInfo::EK_BlockAddress: {
Register TReg = MRI.createVirtualRegister(RC);
Register Tmp1 = MRI.createVirtualRegister(RC);
BuildMI(DispContBB, DL, TII->get(VE::SLLri), Tmp1)
.addReg(IReg, getKillRegState(true))
.addImm(3);
BuildMI(DispContBB, DL, TII->get(VE::LDrri), TReg)
.addReg(BReg, getKillRegState(true))
.addReg(Tmp1, getKillRegState(true))
.addImm(0);
BuildMI(DispContBB, DL, TII->get(VE::BCFLari_t))
.addReg(TReg, getKillRegState(true))
.addImm(0);
break;
}
case MachineJumpTableInfo::EK_Custom32: {
assert(isPositionIndependent());
Register OReg = MRI.createVirtualRegister(RC);
Register TReg = MRI.createVirtualRegister(RC);
Register Tmp1 = MRI.createVirtualRegister(RC);
BuildMI(DispContBB, DL, TII->get(VE::SLLri), Tmp1)
.addReg(IReg, getKillRegState(true))
.addImm(2);
BuildMI(DispContBB, DL, TII->get(VE::LDLZXrri), OReg)
.addReg(BReg, getKillRegState(true))
.addReg(Tmp1, getKillRegState(true))
.addImm(0);
Register BReg2 =
prepareSymbol(*DispContBB, DispContBB->end(),
DispContBB->getParent()->getName(), DL, true);
BuildMI(DispContBB, DL, TII->get(VE::ADDSLrr), TReg)
.addReg(OReg, getKillRegState(true))
.addReg(BReg2, getKillRegState(true));
BuildMI(DispContBB, DL, TII->get(VE::BCFLari_t))
.addReg(TReg, getKillRegState(true))
.addImm(0);
break;
}
default:
llvm_unreachable("Unexpected jump table encoding");
}
SmallPtrSet<MachineBasicBlock *, 8> SeenMBBs;
for (auto &LP : LPadList)
if (SeenMBBs.insert(LP).second)
DispContBB->addSuccessor(LP);
SmallVector<MachineBasicBlock *, 64> MBBLPads;
const MCPhysReg *SavedRegs = MF->getRegInfo().getCalleeSavedRegs();
for (MachineBasicBlock *MBB : InvokeBBs) {
SmallVector<MachineBasicBlock *, 8> Successors(MBB->succ_rbegin(),
MBB->succ_rend());
for (auto MBBS : Successors) {
if (MBBS->isEHPad()) {
MBB->removeSuccessor(MBBS);
MBBLPads.push_back(MBBS);
}
}
MBB->addSuccessor(DispatchBB);
for (auto &II : reverse(*MBB)) {
if (!II.isCall())
continue;
DenseMap<Register, bool> DefRegs;
for (auto &MOp : II.operands())
if (MOp.isReg())
DefRegs[MOp.getReg()] = true;
MachineInstrBuilder MIB(*MF, &II);
for (unsigned RI = 0; SavedRegs[RI]; ++RI) {
Register Reg = SavedRegs[RI];
if (!DefRegs[Reg])
MIB.addReg(Reg, RegState::ImplicitDefine | RegState::Dead);
}
break;
}
}
for (auto &LP : MBBLPads)
LP->setIsEHPad(false);
MI.eraseFromParent();
return BB;
}
MachineBasicBlock *
VETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const {
switch (MI.getOpcode()) {
default:
llvm_unreachable("Unknown Custom Instruction!");
case VE::EH_SjLj_LongJmp:
return emitEHSjLjLongJmp(MI, BB);
case VE::EH_SjLj_SetJmp:
return emitEHSjLjSetJmp(MI, BB);
case VE::EH_SjLj_Setup_Dispatch:
return emitSjLjDispatchBlock(MI, BB);
}
}
static bool isI32Insn(const SDNode *User, const SDNode *N) {
switch (User->getOpcode()) {
default:
return false;
case ISD::ADD:
case ISD::SUB:
case ISD::MUL:
case ISD::SDIV:
case ISD::UDIV:
case ISD::SETCC:
case ISD::SMIN:
case ISD::SMAX:
case ISD::SHL:
case ISD::SRA:
case ISD::BSWAP:
case ISD::SINT_TO_FP:
case ISD::UINT_TO_FP:
case ISD::BR_CC:
case ISD::BITCAST:
case ISD::ATOMIC_CMP_SWAP:
case ISD::ATOMIC_SWAP:
return true;
case ISD::SRL:
if (N->getOperand(0).getOpcode() != ISD::SRL)
return true;
return false;
case ISD::SELECT_CC:
if (User->getOperand(2).getNode() != N &&
User->getOperand(3).getNode() != N)
return true;
LLVM_FALLTHROUGH;
case ISD::AND:
case ISD::OR:
case ISD::XOR:
case ISD::SELECT:
case ISD::CopyToReg:
for (const SDNode *U : User->uses()) {
switch (U->getOpcode()) {
default:
if (isI32Insn(U, N))
continue;
break;
case ISD::ANY_EXTEND:
case ISD::SIGN_EXTEND:
case ISD::ZERO_EXTEND: {
assert(N->getValueType(0) == MVT::i32 &&
"find truncate to not i32 integer");
if (User->getOpcode() == ISD::SELECT_CC ||
User->getOpcode() == ISD::SELECT)
continue;
break;
}
}
return false;
}
return true;
}
}
SDValue VETargetLowering::combineTRUNCATE(SDNode *N,
DAGCombinerInfo &DCI) const {
assert(N->getOpcode() == ISD::TRUNCATE &&
"Should be called with a TRUNCATE node");
SelectionDAG &DAG = DCI.DAG;
SDLoc DL(N);
EVT VT = N->getValueType(0);
if (!DCI.isAfterLegalizeDAG())
return SDValue();
if (N->getOperand(0)->getOpcode() == ISD::SELECT_CC &&
isa<ConstantSDNode>(N->getOperand(0)->getOperand(0)) &&
isa<ConstantSDNode>(N->getOperand(0)->getOperand(1)))
return SDValue();
for (const SDNode *User : N->uses()) {
if (isI32Insn(User, N))
continue;
return SDValue();
}
SDValue SubI32 = DAG.getTargetConstant(VE::sub_i32, DL, MVT::i32);
return SDValue(DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, VT,
N->getOperand(0), SubI32),
0);
}
SDValue VETargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
switch (N->getOpcode()) {
default:
break;
case ISD::TRUNCATE:
return combineTRUNCATE(N, DCI);
}
return SDValue();
}
VETargetLowering::ConstraintType
VETargetLowering::getConstraintType(StringRef Constraint) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
default:
break;
case 'v': return C_RegisterClass;
}
}
return TargetLowering::getConstraintType(Constraint);
}
std::pair<unsigned, const TargetRegisterClass *>
VETargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint,
MVT VT) const {
const TargetRegisterClass *RC = nullptr;
if (Constraint.size() == 1) {
switch (Constraint[0]) {
default:
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
case 'r':
RC = &VE::I64RegClass;
break;
case 'v':
RC = &VE::V64RegClass;
break;
}
return std::make_pair(0U, RC);
}
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
}
unsigned VETargetLowering::getMinimumJumpTableEntries() const {
if (isJumpTableRelative())
return 8;
return TargetLowering::getMinimumJumpTableEntries();
}
bool VETargetLowering::hasAndNot(SDValue Y) const {
EVT VT = Y.getValueType();
if (VT.isVector())
return false;
if (isa<ConstantSDNode>(Y))
return false;
return true;
}
SDValue VETargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
SelectionDAG &DAG) const {
assert(Op.getOpcode() == ISD::EXTRACT_VECTOR_ELT && "Unknown opcode!");
MVT VT = Op.getOperand(0).getSimpleValueType();
assert(VT == MVT::v512i32 || VT == MVT::v512f32);
(void)VT;
SDValue Vec = Op.getOperand(0);
SDValue Idx = Op.getOperand(1);
SDLoc DL(Op);
SDValue Result = Op;
if (false ) {
} else {
SDValue Const1 = DAG.getConstant(1, DL, MVT::i64);
SDValue HalfIdx = DAG.getNode(ISD::SRL, DL, MVT::i64, {Idx, Const1});
SDValue PackedElt =
SDValue(DAG.getMachineNode(VE::LVSvr, DL, MVT::i64, {Vec, HalfIdx}), 0);
SDValue AndIdx = DAG.getNode(ISD::AND, DL, MVT::i64, {Idx, Const1});
SDValue Shift = DAG.getNode(ISD::XOR, DL, MVT::i64, {AndIdx, Const1});
SDValue Const5 = DAG.getConstant(5, DL, MVT::i64);
Shift = DAG.getNode(ISD::SHL, DL, MVT::i64, {Shift, Const5});
PackedElt = DAG.getNode(ISD::SRL, DL, MVT::i64, {PackedElt, Shift});
SDValue Mask = DAG.getConstant(0xFFFFFFFFL, DL, MVT::i64);
PackedElt = DAG.getNode(ISD::AND, DL, MVT::i64, {PackedElt, Mask});
SDValue SubI32 = DAG.getTargetConstant(VE::sub_i32, DL, MVT::i32);
Result = SDValue(DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
MVT::i32, PackedElt, SubI32),
0);
if (Op.getSimpleValueType() == MVT::f32) {
Result = DAG.getBitcast(MVT::f32, Result);
} else {
assert(Op.getSimpleValueType() == MVT::i32);
}
}
return Result;
}
SDValue VETargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
SelectionDAG &DAG) const {
assert(Op.getOpcode() == ISD::INSERT_VECTOR_ELT && "Unknown opcode!");
MVT VT = Op.getOperand(0).getSimpleValueType();
assert(VT == MVT::v512i32 || VT == MVT::v512f32);
(void)VT;
SDLoc DL(Op);
SDValue Vec = Op.getOperand(0);
SDValue Val = Op.getOperand(1);
SDValue Idx = Op.getOperand(2);
if (Idx.getSimpleValueType() == MVT::i32)
Idx = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Idx);
if (Val.getSimpleValueType() == MVT::f32)
Val = DAG.getBitcast(MVT::i32, Val);
assert(Val.getSimpleValueType() == MVT::i32);
Val = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Val);
SDValue Result = Op;
if (false ) {
} else {
SDValue Const1 = DAG.getConstant(1, DL, MVT::i64);
SDValue HalfIdx = DAG.getNode(ISD::SRL, DL, MVT::i64, {Idx, Const1});
SDValue PackedElt =
SDValue(DAG.getMachineNode(VE::LVSvr, DL, MVT::i64, {Vec, HalfIdx}), 0);
SDValue AndIdx = DAG.getNode(ISD::AND, DL, MVT::i64, {Idx, Const1});
SDValue Shift = DAG.getNode(ISD::XOR, DL, MVT::i64, {AndIdx, Const1});
SDValue Const5 = DAG.getConstant(5, DL, MVT::i64);
Shift = DAG.getNode(ISD::SHL, DL, MVT::i64, {Shift, Const5});
SDValue Mask = DAG.getConstant(0xFFFFFFFF00000000L, DL, MVT::i64);
Mask = DAG.getNode(ISD::SRL, DL, MVT::i64, {Mask, Shift});
PackedElt = DAG.getNode(ISD::AND, DL, MVT::i64, {PackedElt, Mask});
Val = DAG.getNode(ISD::SHL, DL, MVT::i64, {Val, Shift});
PackedElt = DAG.getNode(ISD::OR, DL, MVT::i64, {PackedElt, Val});
Result =
SDValue(DAG.getMachineNode(VE::LSVrr_v, DL, Vec.getSimpleValueType(),
{HalfIdx, PackedElt, Vec}),
0);
}
return Result;
}