#include "HexagonISelLowering.h"
#include "Hexagon.h"
#include "HexagonMachineFunctionInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonTargetObjectFile.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RuntimeLibcalls.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/TargetCallingConv.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsHexagon.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "hexagon-lowering"
static cl::opt<bool> EmitJumpTables("hexagon-emit-jump-tables",
cl::init(true), cl::Hidden,
cl::desc("Control jump table emission on Hexagon target"));
static cl::opt<bool>
EnableHexSDNodeSched("enable-hexagon-sdnode-sched", cl::Hidden,
cl::desc("Enable Hexagon SDNode scheduling"));
static cl::opt<bool> EnableFastMath("ffast-math", cl::Hidden,
cl::desc("Enable Fast Math processing"));
static cl::opt<int> MinimumJumpTables("minimum-jump-tables", cl::Hidden,
cl::init(5),
cl::desc("Set minimum jump tables"));
static cl::opt<int>
MaxStoresPerMemcpyCL("max-store-memcpy", cl::Hidden, cl::init(6),
cl::desc("Max #stores to inline memcpy"));
static cl::opt<int>
MaxStoresPerMemcpyOptSizeCL("max-store-memcpy-Os", cl::Hidden, cl::init(4),
cl::desc("Max #stores to inline memcpy"));
static cl::opt<int>
MaxStoresPerMemmoveCL("max-store-memmove", cl::Hidden, cl::init(6),
cl::desc("Max #stores to inline memmove"));
static cl::opt<int>
MaxStoresPerMemmoveOptSizeCL("max-store-memmove-Os", cl::Hidden,
cl::init(4),
cl::desc("Max #stores to inline memmove"));
static cl::opt<int>
MaxStoresPerMemsetCL("max-store-memset", cl::Hidden, cl::init(8),
cl::desc("Max #stores to inline memset"));
static cl::opt<int>
MaxStoresPerMemsetOptSizeCL("max-store-memset-Os", cl::Hidden, cl::init(4),
cl::desc("Max #stores to inline memset"));
static cl::opt<bool> AlignLoads("hexagon-align-loads",
cl::Hidden, cl::init(false),
cl::desc("Rewrite unaligned loads as a pair of aligned loads"));
static cl::opt<bool>
DisableArgsMinAlignment("hexagon-disable-args-min-alignment", cl::Hidden,
cl::init(false),
cl::desc("Disable minimum alignment of 1 for "
"arguments passed by value on stack"));
namespace {
class HexagonCCState : public CCState {
unsigned NumNamedVarArgParams = 0;
public:
HexagonCCState(CallingConv::ID CC, bool IsVarArg, MachineFunction &MF,
SmallVectorImpl<CCValAssign> &locs, LLVMContext &C,
unsigned NumNamedArgs)
: CCState(CC, IsVarArg, MF, locs, C),
NumNamedVarArgParams(NumNamedArgs) {}
unsigned getNumNamedVarArgParams() const { return NumNamedVarArgParams; }
};
}
static bool CC_SkipOdd(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
CCValAssign::LocInfo &LocInfo,
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
static const MCPhysReg ArgRegs[] = {
Hexagon::R0, Hexagon::R1, Hexagon::R2,
Hexagon::R3, Hexagon::R4, Hexagon::R5
};
const unsigned NumArgRegs = array_lengthof(ArgRegs);
unsigned RegNum = State.getFirstUnallocated(ArgRegs);
if (RegNum != NumArgRegs && RegNum % 2 == 1)
State.AllocateReg(ArgRegs[RegNum]);
return false;
}
#include "HexagonGenCallingConv.inc"
SDValue
HexagonTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG)
const {
return SDValue();
}
static SDValue CreateCopyOfByValArgument(SDValue Src, SDValue Dst,
SDValue Chain, ISD::ArgFlagsTy Flags,
SelectionDAG &DAG, const SDLoc &dl) {
SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), dl, MVT::i32);
return DAG.getMemcpy(
Chain, dl, Dst, Src, SizeNode, Flags.getNonZeroByValAlign(),
false, false,
false, MachinePointerInfo(), MachinePointerInfo());
}
bool
HexagonTargetLowering::CanLowerReturn(
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
LLVMContext &Context) const {
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
if (MF.getSubtarget<HexagonSubtarget>().useHVXOps())
return CCInfo.CheckReturn(Outs, RetCC_Hexagon_HVX);
return CCInfo.CheckReturn(Outs, RetCC_Hexagon);
}
SDValue
HexagonTargetLowering::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());
if (Subtarget.useHVXOps())
CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon_HVX);
else
CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon);
SDValue Flag;
SmallVector<SDValue, 4> RetOps(1, Chain);
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
SDValue Val = OutVals[i];
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unknown loc info!");
case CCValAssign::Full:
break;
case CCValAssign::BCvt:
Val = DAG.getBitcast(VA.getLocVT(), Val);
break;
case CCValAssign::SExt:
Val = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Val);
break;
case CCValAssign::ZExt:
Val = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Val);
break;
case CCValAssign::AExt:
Val = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Val);
break;
}
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Val, 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(HexagonISD::RET_FLAG, dl, MVT::Other, RetOps);
}
bool HexagonTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
return CI->isTailCall();
}
Register HexagonTargetLowering::getRegisterByName(
const char* RegName, LLT VT, const MachineFunction &) const {
Register Reg = StringSwitch<Register>(RegName)
.Case("r0", Hexagon::R0)
.Case("r1", Hexagon::R1)
.Case("r2", Hexagon::R2)
.Case("r3", Hexagon::R3)
.Case("r4", Hexagon::R4)
.Case("r5", Hexagon::R5)
.Case("r6", Hexagon::R6)
.Case("r7", Hexagon::R7)
.Case("r8", Hexagon::R8)
.Case("r9", Hexagon::R9)
.Case("r10", Hexagon::R10)
.Case("r11", Hexagon::R11)
.Case("r12", Hexagon::R12)
.Case("r13", Hexagon::R13)
.Case("r14", Hexagon::R14)
.Case("r15", Hexagon::R15)
.Case("r16", Hexagon::R16)
.Case("r17", Hexagon::R17)
.Case("r18", Hexagon::R18)
.Case("r19", Hexagon::R19)
.Case("r20", Hexagon::R20)
.Case("r21", Hexagon::R21)
.Case("r22", Hexagon::R22)
.Case("r23", Hexagon::R23)
.Case("r24", Hexagon::R24)
.Case("r25", Hexagon::R25)
.Case("r26", Hexagon::R26)
.Case("r27", Hexagon::R27)
.Case("r28", Hexagon::R28)
.Case("r29", Hexagon::R29)
.Case("r30", Hexagon::R30)
.Case("r31", Hexagon::R31)
.Case("r1:0", Hexagon::D0)
.Case("r3:2", Hexagon::D1)
.Case("r5:4", Hexagon::D2)
.Case("r7:6", Hexagon::D3)
.Case("r9:8", Hexagon::D4)
.Case("r11:10", Hexagon::D5)
.Case("r13:12", Hexagon::D6)
.Case("r15:14", Hexagon::D7)
.Case("r17:16", Hexagon::D8)
.Case("r19:18", Hexagon::D9)
.Case("r21:20", Hexagon::D10)
.Case("r23:22", Hexagon::D11)
.Case("r25:24", Hexagon::D12)
.Case("r27:26", Hexagon::D13)
.Case("r29:28", Hexagon::D14)
.Case("r31:30", Hexagon::D15)
.Case("sp", Hexagon::R29)
.Case("fp", Hexagon::R30)
.Case("lr", Hexagon::R31)
.Case("p0", Hexagon::P0)
.Case("p1", Hexagon::P1)
.Case("p2", Hexagon::P2)
.Case("p3", Hexagon::P3)
.Case("sa0", Hexagon::SA0)
.Case("lc0", Hexagon::LC0)
.Case("sa1", Hexagon::SA1)
.Case("lc1", Hexagon::LC1)
.Case("m0", Hexagon::M0)
.Case("m1", Hexagon::M1)
.Case("usr", Hexagon::USR)
.Case("ugp", Hexagon::UGP)
.Case("cs0", Hexagon::CS0)
.Case("cs1", Hexagon::CS1)
.Default(Register());
if (Reg)
return Reg;
report_fatal_error("Invalid register name global variable");
}
SDValue HexagonTargetLowering::LowerCallResult(
SDValue Chain, SDValue Glue, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals,
const SmallVectorImpl<SDValue> &OutVals, SDValue Callee) const {
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
if (Subtarget.useHVXOps())
CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon_HVX);
else
CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon);
for (unsigned i = 0; i != RVLocs.size(); ++i) {
SDValue RetVal;
if (RVLocs[i].getValVT() == MVT::i1) {
auto &MRI = DAG.getMachineFunction().getRegInfo();
SDValue FR0 = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(),
MVT::i32, Glue);
Register PredR = MRI.createVirtualRegister(&Hexagon::PredRegsRegClass);
SDValue TPR = DAG.getCopyToReg(FR0.getValue(1), dl, PredR,
FR0.getValue(0), FR0.getValue(2));
RetVal = DAG.getCopyFromReg(TPR.getValue(0), dl, PredR, MVT::i1);
Glue = TPR.getValue(1);
Chain = TPR.getValue(0);
} else {
RetVal = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(),
RVLocs[i].getValVT(), Glue);
Glue = RetVal.getValue(2);
Chain = RetVal.getValue(1);
}
InVals.push_back(RetVal.getValue(0));
}
return Chain;
}
SDValue
HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
SelectionDAG &DAG = CLI.DAG;
SDLoc &dl = CLI.DL;
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
SDValue Chain = CLI.Chain;
SDValue Callee = CLI.Callee;
CallingConv::ID CallConv = CLI.CallConv;
bool IsVarArg = CLI.IsVarArg;
bool DoesNotReturn = CLI.DoesNotReturn;
bool IsStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
auto PtrVT = getPointerTy(MF.getDataLayout());
unsigned NumParams = CLI.CB ? CLI.CB->getFunctionType()->getNumParams() : 0;
if (GlobalAddressSDNode *GAN = dyn_cast<GlobalAddressSDNode>(Callee))
Callee = DAG.getTargetGlobalAddress(GAN->getGlobal(), dl, MVT::i32);
bool TreatAsVarArg = !Subtarget.isEnvironmentMusl() && IsVarArg;
SmallVector<CCValAssign, 16> ArgLocs;
HexagonCCState CCInfo(CallConv, TreatAsVarArg, MF, ArgLocs, *DAG.getContext(),
NumParams);
if (Subtarget.useHVXOps())
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_HVX);
else if (DisableArgsMinAlignment)
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_Legacy);
else
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon);
if (CLI.IsTailCall) {
bool StructAttrFlag = MF.getFunction().hasStructRetAttr();
CLI.IsTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
IsVarArg, IsStructRet, StructAttrFlag, Outs,
OutVals, Ins, DAG);
for (const CCValAssign &VA : ArgLocs) {
if (VA.isMemLoc()) {
CLI.IsTailCall = false;
break;
}
}
LLVM_DEBUG(dbgs() << (CLI.IsTailCall ? "Eligible for Tail Call\n"
: "Argument must be passed on stack. "
"Not eligible for Tail Call\n"));
}
unsigned NumBytes = CCInfo.getNextStackOffset();
SmallVector<std::pair<unsigned, SDValue>, 16> RegsToPass;
SmallVector<SDValue, 8> MemOpChains;
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
SDValue StackPtr =
DAG.getCopyFromReg(Chain, dl, HRI.getStackRegister(), PtrVT);
bool NeedsArgAlign = false;
Align LargestAlignSeen;
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
SDValue Arg = OutVals[i];
ISD::ArgFlagsTy Flags = Outs[i].Flags;
bool ArgAlign = Subtarget.isHVXVectorType(VA.getValVT());
NeedsArgAlign |= ArgAlign;
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unknown loc info!");
case CCValAssign::Full:
break;
case CCValAssign::BCvt:
Arg = DAG.getBitcast(VA.getLocVT(), Arg);
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;
}
if (VA.isMemLoc()) {
unsigned LocMemOffset = VA.getLocMemOffset();
SDValue MemAddr = DAG.getConstant(LocMemOffset, dl,
StackPtr.getValueType());
MemAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, MemAddr);
if (ArgAlign)
LargestAlignSeen = std::max(
LargestAlignSeen, Align(VA.getLocVT().getStoreSizeInBits() / 8));
if (Flags.isByVal()) {
MemOpChains.push_back(CreateCopyOfByValArgument(Arg, MemAddr, Chain,
Flags, DAG, dl));
} else {
MachinePointerInfo LocPI = MachinePointerInfo::getStack(
DAG.getMachineFunction(), LocMemOffset);
SDValue S = DAG.getStore(Chain, dl, Arg, MemAddr, LocPI);
MemOpChains.push_back(S);
}
continue;
}
if (VA.isRegLoc())
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
}
if (NeedsArgAlign && Subtarget.hasV60Ops()) {
LLVM_DEBUG(dbgs() << "Function needs byte stack align due to call args\n");
Align VecAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
LargestAlignSeen = std::max(LargestAlignSeen, VecAlign);
MFI.ensureMaxAlignment(LargestAlignSeen);
}
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
SDValue Glue;
if (!CLI.IsTailCall) {
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl);
Glue = Chain.getValue(1);
}
if (!CLI.IsTailCall) {
for (const auto &R : RegsToPass) {
Chain = DAG.getCopyToReg(Chain, dl, R.first, R.second, Glue);
Glue = Chain.getValue(1);
}
} else {
Glue = SDValue();
for (const auto &R : RegsToPass) {
Chain = DAG.getCopyToReg(Chain, dl, R.first, R.second, Glue);
Glue = Chain.getValue(1);
}
Glue = SDValue();
}
bool LongCalls = MF.getSubtarget<HexagonSubtarget>().useLongCalls();
unsigned Flags = LongCalls ? HexagonII::HMOTF_ConstExtended : 0;
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, PtrVT, 0, Flags);
} else if (ExternalSymbolSDNode *S =
dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, Flags);
}
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
for (const auto &R : RegsToPass)
Ops.push_back(DAG.getRegister(R.first, R.second.getValueType()));
const uint32_t *Mask = HRI.getCallPreservedMask(MF, CallConv);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));
if (Glue.getNode())
Ops.push_back(Glue);
if (CLI.IsTailCall) {
MFI.setHasTailCall();
return DAG.getNode(HexagonISD::TC_RETURN, dl, NodeTys, Ops);
}
MFI.setHasCalls(true);
unsigned OpCode = DoesNotReturn ? HexagonISD::CALLnr : HexagonISD::CALL;
Chain = DAG.getNode(OpCode, dl, NodeTys, Ops);
Glue = Chain.getValue(1);
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, dl, true),
DAG.getIntPtrConstant(0, dl, true), Glue, dl);
Glue = Chain.getValue(1);
return LowerCallResult(Chain, Glue, CallConv, IsVarArg, Ins, dl, DAG,
InVals, OutVals, Callee);
}
bool HexagonTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
SDValue &Base, SDValue &Offset, ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const {
LSBaseSDNode *LSN = dyn_cast<LSBaseSDNode>(N);
if (!LSN)
return false;
EVT VT = LSN->getMemoryVT();
if (!VT.isSimple())
return false;
bool IsLegalType = VT == MVT::i8 || VT == MVT::i16 || VT == MVT::i32 ||
VT == MVT::i64 || VT == MVT::f32 || VT == MVT::f64 ||
VT == MVT::v2i16 || VT == MVT::v2i32 || VT == MVT::v4i8 ||
VT == MVT::v4i16 || VT == MVT::v8i8 ||
Subtarget.isHVXVectorType(VT.getSimpleVT());
if (!IsLegalType)
return false;
if (Op->getOpcode() != ISD::ADD)
return false;
Base = Op->getOperand(0);
Offset = Op->getOperand(1);
if (!isa<ConstantSDNode>(Offset.getNode()))
return false;
AM = ISD::POST_INC;
int32_t V = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
return Subtarget.getInstrInfo()->isValidAutoIncImm(VT, V);
}
SDValue
HexagonTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
unsigned LR = HRI.getRARegister();
if ((Op.getOpcode() != ISD::INLINEASM &&
Op.getOpcode() != ISD::INLINEASM_BR) || HMFI.hasClobberLR())
return Op;
unsigned NumOps = Op.getNumOperands();
if (Op.getOperand(NumOps-1).getValueType() == MVT::Glue)
--NumOps;
for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) {
unsigned Flags = cast<ConstantSDNode>(Op.getOperand(i))->getZExtValue();
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
++i;
switch (InlineAsm::getKind(Flags)) {
default:
llvm_unreachable("Bad flags!");
case InlineAsm::Kind_RegUse:
case InlineAsm::Kind_Imm:
case InlineAsm::Kind_Mem:
i += NumVals;
break;
case InlineAsm::Kind_Clobber:
case InlineAsm::Kind_RegDef:
case InlineAsm::Kind_RegDefEarlyClobber: {
for (; NumVals; --NumVals, ++i) {
Register Reg = cast<RegisterSDNode>(Op.getOperand(i))->getReg();
if (Reg != LR)
continue;
HMFI.setHasClobberLR(true);
return Op;
}
break;
}
}
}
return Op;
}
SDValue HexagonTargetLowering::LowerPREFETCH(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDValue Addr = Op.getOperand(1);
SDLoc DL(Op);
SDValue Zero = DAG.getConstant(0, DL, MVT::i32);
return DAG.getNode(HexagonISD::DCFETCH, DL, MVT::Other, Chain, Addr, Zero);
}
SDValue HexagonTargetLowering::LowerREADCYCLECOUNTER(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDLoc dl(Op);
SDVTList VTs = DAG.getVTList(MVT::i64, MVT::Other);
return DAG.getNode(HexagonISD::READCYCLE, dl, VTs, Chain);
}
SDValue HexagonTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
if (IntNo == Intrinsic::hexagon_prefetch) {
SDValue Addr = Op.getOperand(2);
SDLoc DL(Op);
SDValue Zero = DAG.getConstant(0, DL, MVT::i32);
return DAG.getNode(HexagonISD::DCFETCH, DL, MVT::Other, Chain, Addr, Zero);
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDValue Size = Op.getOperand(1);
SDValue Align = Op.getOperand(2);
SDLoc dl(Op);
ConstantSDNode *AlignConst = dyn_cast<ConstantSDNode>(Align);
assert(AlignConst && "Non-constant Align in LowerDYNAMIC_STACKALLOC");
unsigned A = AlignConst->getSExtValue();
auto &HFI = *Subtarget.getFrameLowering();
if (A == 0)
A = HFI.getStackAlign().value();
LLVM_DEBUG({
dbgs () << __func__ << " Align: " << A << " Size: ";
Size.getNode()->dump(&DAG);
dbgs() << "\n";
});
SDValue AC = DAG.getConstant(A, dl, MVT::i32);
SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Other);
SDValue AA = DAG.getNode(HexagonISD::ALLOCA, dl, VTs, Chain, Size, AC);
DAG.ReplaceAllUsesOfValueWith(Op, AA);
return AA;
}
SDValue HexagonTargetLowering::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();
MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
bool TreatAsVarArg = !Subtarget.isEnvironmentMusl() && IsVarArg;
SmallVector<CCValAssign, 16> ArgLocs;
HexagonCCState CCInfo(CallConv, TreatAsVarArg, MF, ArgLocs,
*DAG.getContext(),
MF.getFunction().getFunctionType()->getNumParams());
if (Subtarget.useHVXOps())
CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_HVX);
else if (DisableArgsMinAlignment)
CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_Legacy);
else
CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon);
auto NextSingleReg = [] (const TargetRegisterClass &RC, unsigned Reg) {
switch (RC.getID()) {
case Hexagon::IntRegsRegClassID:
return Reg - Hexagon::R0 + 1;
case Hexagon::DoubleRegsRegClassID:
return (Reg - Hexagon::D0 + 1) * 2;
case Hexagon::HvxVRRegClassID:
return Reg - Hexagon::V0 + 1;
case Hexagon::HvxWRRegClassID:
return (Reg - Hexagon::W0 + 1) * 2;
}
llvm_unreachable("Unexpected register class");
};
auto &HFL = const_cast<HexagonFrameLowering&>(*Subtarget.getFrameLowering());
auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
HFL.FirstVarArgSavedReg = 0;
HMFI.setFirstNamedArgFrameIndex(-int(MFI.getNumFixedObjects()));
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
ISD::ArgFlagsTy Flags = Ins[i].Flags;
bool ByVal = Flags.isByVal();
if (VA.isRegLoc() && ByVal && Flags.getByValSize() <= 8)
llvm_unreachable("ByValSize must be bigger than 8 bytes");
bool InReg = VA.isRegLoc() &&
(!ByVal || (ByVal && Flags.getByValSize() > 8));
if (InReg) {
MVT RegVT = VA.getLocVT();
if (VA.getLocInfo() == CCValAssign::BCvt)
RegVT = VA.getValVT();
const TargetRegisterClass *RC = getRegClassFor(RegVT);
Register VReg = MRI.createVirtualRegister(RC);
SDValue Copy = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
if (VA.getValVT() == MVT::i1) {
assert(RegVT.getSizeInBits() <= 32);
SDValue T = DAG.getNode(ISD::AND, dl, RegVT,
Copy, DAG.getConstant(1, dl, RegVT));
Copy = DAG.getSetCC(dl, MVT::i1, T, DAG.getConstant(0, dl, RegVT),
ISD::SETNE);
} else {
#ifndef NDEBUG
unsigned RegSize = RegVT.getSizeInBits();
assert(RegSize == 32 || RegSize == 64 ||
Subtarget.isHVXVectorType(RegVT));
#endif
}
InVals.push_back(Copy);
MRI.addLiveIn(VA.getLocReg(), VReg);
HFL.FirstVarArgSavedReg = NextSingleReg(*RC, VA.getLocReg());
} else {
assert(VA.isMemLoc() && "Argument should be passed in memory");
unsigned ObjSize = Flags.isByVal()
? Flags.getByValSize()
: VA.getLocVT().getStoreSizeInBits() / 8;
int Offset = HEXAGON_LRFP_SIZE + VA.getLocMemOffset();
int FI = MFI.CreateFixedObject(ObjSize, Offset, true);
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
if (Flags.isByVal()) {
InVals.push_back(FIN);
} else {
SDValue L = DAG.getLoad(VA.getValVT(), dl, Chain, FIN,
MachinePointerInfo::getFixedStack(MF, FI, 0));
InVals.push_back(L);
}
}
}
if (IsVarArg && Subtarget.isEnvironmentMusl()) {
for (int i = HFL.FirstVarArgSavedReg; i < 6; i++)
MRI.addLiveIn(Hexagon::R0+i);
}
if (IsVarArg && Subtarget.isEnvironmentMusl()) {
HMFI.setFirstNamedArgFrameIndex(HMFI.getFirstNamedArgFrameIndex() - 1);
HMFI.setLastNamedArgFrameIndex(-int(MFI.getNumFixedObjects()));
int NumVarArgRegs = 6 - HFL.FirstVarArgSavedReg;
bool RequiresPadding = (NumVarArgRegs & 1);
int RegSaveAreaSizePlusPadding = RequiresPadding
? (NumVarArgRegs + 1) * 4
: NumVarArgRegs * 4;
if (RegSaveAreaSizePlusPadding > 0) {
int RegAreaStart = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset();
if (!(RegAreaStart % 8))
RegAreaStart = (RegAreaStart + 7) & -8;
int RegSaveAreaFrameIndex =
MFI.CreateFixedObject(RegSaveAreaSizePlusPadding, RegAreaStart, true);
HMFI.setRegSavedAreaStartFrameIndex(RegSaveAreaFrameIndex);
int Offset = RegAreaStart + RegSaveAreaSizePlusPadding;
int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true);
HMFI.setVarArgsFrameIndex(FI);
} else {
int Offset = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset();
int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true);
HMFI.setRegSavedAreaStartFrameIndex(FI);
HMFI.setVarArgsFrameIndex(FI);
}
}
if (IsVarArg && !Subtarget.isEnvironmentMusl()) {
int Offset = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset();
int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true);
HMFI.setVarArgsFrameIndex(FI);
}
return Chain;
}
SDValue
HexagonTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
HexagonMachineFunctionInfo *QFI = MF.getInfo<HexagonMachineFunctionInfo>();
SDValue Addr = DAG.getFrameIndex(QFI->getVarArgsFrameIndex(), MVT::i32);
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
if (!Subtarget.isEnvironmentMusl()) {
return DAG.getStore(Op.getOperand(0), SDLoc(Op), Addr, Op.getOperand(1),
MachinePointerInfo(SV));
}
auto &FuncInfo = *MF.getInfo<HexagonMachineFunctionInfo>();
auto &HFL = *Subtarget.getFrameLowering();
SDLoc DL(Op);
SmallVector<SDValue, 8> MemOps;
SDValue FIN = Op.getOperand(1);
SDValue SavedRegAreaStartFrameIndex =
DAG.getFrameIndex(FuncInfo.getRegSavedAreaStartFrameIndex(), MVT::i32);
auto PtrVT = getPointerTy(DAG.getDataLayout());
if (HFL.FirstVarArgSavedReg & 1)
SavedRegAreaStartFrameIndex =
DAG.getNode(ISD::ADD, DL, PtrVT,
DAG.getFrameIndex(FuncInfo.getRegSavedAreaStartFrameIndex(),
MVT::i32),
DAG.getIntPtrConstant(4, DL));
SDValue Store =
DAG.getStore(Op.getOperand(0), DL,
SavedRegAreaStartFrameIndex,
FIN, MachinePointerInfo(SV));
MemOps.push_back(Store);
FIN = DAG.getNode(ISD::ADD, DL, PtrVT,
FIN, DAG.getIntPtrConstant(4, DL));
Store = DAG.getStore(Op.getOperand(0), DL,
DAG.getFrameIndex(FuncInfo.getVarArgsFrameIndex(),
PtrVT),
FIN, MachinePointerInfo(SV, 4));
MemOps.push_back(Store);
FIN = DAG.getNode(ISD::ADD, DL, PtrVT,
FIN, DAG.getIntPtrConstant(4, DL));
Store = DAG.getStore(Op.getOperand(0), DL,
DAG.getFrameIndex(FuncInfo.getVarArgsFrameIndex(),
PtrVT),
FIN, MachinePointerInfo(SV, 8));
MemOps.push_back(Store);
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps);
}
SDValue
HexagonTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const {
assert(Subtarget.isEnvironmentMusl() && "Linux ABI should be enabled");
SDValue Chain = Op.getOperand(0);
SDValue DestPtr = Op.getOperand(1);
SDValue SrcPtr = Op.getOperand(2);
const Value *DestSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
SDLoc DL(Op);
return DAG.getMemcpy(Chain, DL, DestPtr, SrcPtr,
DAG.getIntPtrConstant(12, DL), Align(4),
false, false, false,
MachinePointerInfo(DestSV), MachinePointerInfo(SrcSV));
}
SDValue HexagonTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
const SDLoc &dl(Op);
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
MVT ResTy = ty(Op);
MVT OpTy = ty(LHS);
if (OpTy == MVT::v2i16 || OpTy == MVT::v4i8) {
MVT ElemTy = OpTy.getVectorElementType();
assert(ElemTy.isScalarInteger());
MVT WideTy = MVT::getVectorVT(MVT::getIntegerVT(2*ElemTy.getSizeInBits()),
OpTy.getVectorNumElements());
return DAG.getSetCC(dl, ResTy,
DAG.getSExtOrTrunc(LHS, SDLoc(LHS), WideTy),
DAG.getSExtOrTrunc(RHS, SDLoc(RHS), WideTy), CC);
}
if (ResTy.isVector())
return Op;
auto isSExtFree = [this](SDValue N) {
switch (N.getOpcode()) {
case ISD::TRUNCATE: {
SDValue Op = N.getOperand(0);
if (Op.getOpcode() != ISD::AssertSext)
return false;
EVT OrigTy = cast<VTSDNode>(Op.getOperand(1))->getVT();
unsigned ThisBW = ty(N).getSizeInBits();
unsigned OrigBW = OrigTy.getSizeInBits();
return ThisBW >= OrigBW;
}
case ISD::LOAD:
return true;
}
return false;
};
if (OpTy == MVT::i8 || OpTy == MVT::i16) {
ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS);
bool IsNegative = C && C->getAPIntValue().isNegative();
if (IsNegative || isSExtFree(LHS) || isSExtFree(RHS))
return DAG.getSetCC(dl, ResTy,
DAG.getSExtOrTrunc(LHS, SDLoc(LHS), MVT::i32),
DAG.getSExtOrTrunc(RHS, SDLoc(RHS), MVT::i32), CC);
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerVSELECT(SDValue Op, SelectionDAG &DAG) const {
SDValue PredOp = Op.getOperand(0);
SDValue Op1 = Op.getOperand(1), Op2 = Op.getOperand(2);
MVT OpTy = ty(Op1);
const SDLoc &dl(Op);
if (OpTy == MVT::v2i16 || OpTy == MVT::v4i8) {
MVT ElemTy = OpTy.getVectorElementType();
assert(ElemTy.isScalarInteger());
MVT WideTy = MVT::getVectorVT(MVT::getIntegerVT(2*ElemTy.getSizeInBits()),
OpTy.getVectorNumElements());
return DAG.getSExtOrTrunc(
DAG.getSelect(dl, WideTy, PredOp,
DAG.getSExtOrTrunc(Op1, dl, WideTy),
DAG.getSExtOrTrunc(Op2, dl, WideTy)),
dl, OpTy);
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const {
EVT ValTy = Op.getValueType();
ConstantPoolSDNode *CPN = cast<ConstantPoolSDNode>(Op);
Constant *CVal = nullptr;
bool isVTi1Type = false;
if (auto *CV = dyn_cast<ConstantVector>(CPN->getConstVal())) {
if (cast<VectorType>(CV->getType())->getElementType()->isIntegerTy(1)) {
IRBuilder<> IRB(CV->getContext());
SmallVector<Constant*, 128> NewConst;
unsigned VecLen = CV->getNumOperands();
assert(isPowerOf2_32(VecLen) &&
"conversion only supported for pow2 VectorSize");
for (unsigned i = 0; i < VecLen; ++i)
NewConst.push_back(IRB.getInt8(CV->getOperand(i)->isZeroValue()));
CVal = ConstantVector::get(NewConst);
isVTi1Type = true;
}
}
Align Alignment = CPN->getAlign();
bool IsPositionIndependent = isPositionIndependent();
unsigned char TF = IsPositionIndependent ? HexagonII::MO_PCREL : 0;
unsigned Offset = 0;
SDValue T;
if (CPN->isMachineConstantPoolEntry())
T = DAG.getTargetConstantPool(CPN->getMachineCPVal(), ValTy, Alignment,
Offset, TF);
else if (isVTi1Type)
T = DAG.getTargetConstantPool(CVal, ValTy, Alignment, Offset, TF);
else
T = DAG.getTargetConstantPool(CPN->getConstVal(), ValTy, Alignment, Offset,
TF);
assert(cast<ConstantPoolSDNode>(T)->getTargetFlags() == TF &&
"Inconsistent target flag encountered");
if (IsPositionIndependent)
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), ValTy, T);
return DAG.getNode(HexagonISD::CP, SDLoc(Op), ValTy, T);
}
SDValue
HexagonTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
EVT VT = Op.getValueType();
int Idx = cast<JumpTableSDNode>(Op)->getIndex();
if (isPositionIndependent()) {
SDValue T = DAG.getTargetJumpTable(Idx, VT, HexagonII::MO_PCREL);
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), VT, T);
}
SDValue T = DAG.getTargetJumpTable(Idx, VT);
return DAG.getNode(HexagonISD::JT, SDLoc(Op), VT, T);
}
SDValue
HexagonTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
EVT VT = Op.getValueType();
SDLoc dl(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
if (Depth) {
SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
SDValue Offset = DAG.getConstant(4, dl, MVT::i32);
return DAG.getLoad(VT, dl, DAG.getEntryNode(),
DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset),
MachinePointerInfo());
}
Register Reg = MF.addLiveIn(HRI.getRARegister(), getRegClassFor(MVT::i32));
return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT);
}
SDValue
HexagonTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc dl(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl,
HRI.getFrameRegister(), VT);
while (Depth--)
FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr,
MachinePointerInfo());
return FrameAddr;
}
SDValue
HexagonTargetLowering::LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const {
SDLoc dl(Op);
return DAG.getNode(HexagonISD::BARRIER, dl, MVT::Other, Op.getOperand(0));
}
SDValue
HexagonTargetLowering::LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) const {
SDLoc dl(Op);
auto *GAN = cast<GlobalAddressSDNode>(Op);
auto PtrVT = getPointerTy(DAG.getDataLayout());
auto *GV = GAN->getGlobal();
int64_t Offset = GAN->getOffset();
auto &HLOF = *HTM.getObjFileLowering();
Reloc::Model RM = HTM.getRelocationModel();
if (RM == Reloc::Static) {
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, Offset);
const GlobalObject *GO = GV->getAliaseeObject();
if (GO && Subtarget.useSmallData() && HLOF.isGlobalInSmallSection(GO, HTM))
return DAG.getNode(HexagonISD::CONST32_GP, dl, PtrVT, GA);
return DAG.getNode(HexagonISD::CONST32, dl, PtrVT, GA);
}
bool UsePCRel = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV);
if (UsePCRel) {
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, Offset,
HexagonII::MO_PCREL);
return DAG.getNode(HexagonISD::AT_PCREL, dl, PtrVT, GA);
}
SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT);
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, HexagonII::MO_GOT);
SDValue Off = DAG.getConstant(Offset, dl, MVT::i32);
return DAG.getNode(HexagonISD::AT_GOT, dl, PtrVT, GOT, GA, Off);
}
SDValue
HexagonTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const {
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
SDLoc dl(Op);
EVT PtrVT = getPointerTy(DAG.getDataLayout());
Reloc::Model RM = HTM.getRelocationModel();
if (RM == Reloc::Static) {
SDValue A = DAG.getTargetBlockAddress(BA, PtrVT);
return DAG.getNode(HexagonISD::CONST32_GP, dl, PtrVT, A);
}
SDValue A = DAG.getTargetBlockAddress(BA, PtrVT, 0, HexagonII::MO_PCREL);
return DAG.getNode(HexagonISD::AT_PCREL, dl, PtrVT, A);
}
SDValue
HexagonTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG)
const {
EVT PtrVT = getPointerTy(DAG.getDataLayout());
SDValue GOTSym = DAG.getTargetExternalSymbol(HEXAGON_GOT_SYM_NAME, PtrVT,
HexagonII::MO_PCREL);
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), PtrVT, GOTSym);
}
SDValue
HexagonTargetLowering::GetDynamicTLSAddr(SelectionDAG &DAG, SDValue Chain,
GlobalAddressSDNode *GA, SDValue Glue, EVT PtrVT, unsigned ReturnReg,
unsigned char OperandFlags) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SDLoc dl(GA);
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl,
GA->getValueType(0),
GA->getOffset(),
OperandFlags);
const auto &HRI = *Subtarget.getRegisterInfo();
const uint32_t *Mask = HRI.getCallPreservedMask(MF, CallingConv::C);
assert(Mask && "Missing call preserved mask for calling convention");
SDValue Ops[] = { Chain, TGA, DAG.getRegister(Hexagon::R0, PtrVT),
DAG.getRegisterMask(Mask), Glue };
Chain = DAG.getNode(HexagonISD::CALL, dl, NodeTys, Ops);
MFI.setAdjustsStack(true);
Glue = Chain.getValue(1);
return DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Glue);
}
SDValue
HexagonTargetLowering::LowerToTLSInitialExecModel(GlobalAddressSDNode *GA,
SelectionDAG &DAG) const {
SDLoc dl(GA);
int64_t Offset = GA->getOffset();
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue TP = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Hexagon::UGP, PtrVT);
bool IsPositionIndependent = isPositionIndependent();
unsigned char TF =
IsPositionIndependent ? HexagonII::MO_IEGOT : HexagonII::MO_IE;
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT,
Offset, TF);
SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA);
if (IsPositionIndependent) {
SDValue GOT = LowerGLOBAL_OFFSET_TABLE(Sym, DAG);
Sym = DAG.getNode(ISD::ADD, dl, PtrVT, GOT, Sym);
}
SDValue LoadOffset =
DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Sym, MachinePointerInfo());
return DAG.getNode(ISD::ADD, dl, PtrVT, TP, LoadOffset);
}
SDValue
HexagonTargetLowering::LowerToTLSLocalExecModel(GlobalAddressSDNode *GA,
SelectionDAG &DAG) const {
SDLoc dl(GA);
int64_t Offset = GA->getOffset();
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue TP = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Hexagon::UGP, PtrVT);
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, Offset,
HexagonII::MO_TPREL);
SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA);
return DAG.getNode(ISD::ADD, dl, PtrVT, TP, Sym);
}
SDValue
HexagonTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA,
SelectionDAG &DAG) const {
SDLoc dl(GA);
int64_t Offset = GA->getOffset();
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, Offset,
HexagonII::MO_GDGOT);
SDValue GOT = LowerGLOBAL_OFFSET_TABLE(TGA, DAG);
SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA);
SDValue Chain = DAG.getNode(ISD::ADD, dl, PtrVT, GOT, Sym);
SDValue InFlag;
Chain = DAG.getCopyToReg(DAG.getEntryNode(), dl, Hexagon::R0, Chain, InFlag);
InFlag = Chain.getValue(1);
unsigned Flags = DAG.getSubtarget<HexagonSubtarget>().useLongCalls()
? HexagonII::MO_GDPLT | HexagonII::HMOTF_ConstExtended
: HexagonII::MO_GDPLT;
return GetDynamicTLSAddr(DAG, Chain, GA, InFlag, PtrVT,
Hexagon::R0, Flags);
}
SDValue
HexagonTargetLowering::LowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
switch (HTM.getTLSModel(GA->getGlobal())) {
case TLSModel::GeneralDynamic:
case TLSModel::LocalDynamic:
return LowerToTLSGeneralDynamicModel(GA, DAG);
case TLSModel::InitialExec:
return LowerToTLSInitialExecModel(GA, DAG);
case TLSModel::LocalExec:
return LowerToTLSLocalExecModel(GA, DAG);
}
llvm_unreachable("Bogus TLS model");
}
HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
const HexagonSubtarget &ST)
: TargetLowering(TM), HTM(static_cast<const HexagonTargetMachine&>(TM)),
Subtarget(ST) {
auto &HRI = *Subtarget.getRegisterInfo();
setPrefLoopAlignment(Align(16));
setMinFunctionAlignment(Align(4));
setPrefFunctionAlignment(Align(16));
setStackPointerRegisterToSaveRestore(HRI.getStackRegister());
setBooleanContents(TargetLoweringBase::UndefinedBooleanContent);
setBooleanVectorContents(TargetLoweringBase::UndefinedBooleanContent);
setMaxAtomicSizeInBitsSupported(64);
setMinCmpXchgSizeInBits(32);
if (EnableHexSDNodeSched)
setSchedulingPreference(Sched::VLIW);
else
setSchedulingPreference(Sched::Source);
MaxStoresPerMemcpy = MaxStoresPerMemcpyCL;
MaxStoresPerMemcpyOptSize = MaxStoresPerMemcpyOptSizeCL;
MaxStoresPerMemmove = MaxStoresPerMemmoveCL;
MaxStoresPerMemmoveOptSize = MaxStoresPerMemmoveOptSizeCL;
MaxStoresPerMemset = MaxStoresPerMemsetCL;
MaxStoresPerMemsetOptSize = MaxStoresPerMemsetOptSizeCL;
addRegisterClass(MVT::i1, &Hexagon::PredRegsRegClass);
addRegisterClass(MVT::v2i1, &Hexagon::PredRegsRegClass); addRegisterClass(MVT::v4i1, &Hexagon::PredRegsRegClass); addRegisterClass(MVT::v8i1, &Hexagon::PredRegsRegClass); addRegisterClass(MVT::i32, &Hexagon::IntRegsRegClass);
addRegisterClass(MVT::v2i16, &Hexagon::IntRegsRegClass);
addRegisterClass(MVT::v4i8, &Hexagon::IntRegsRegClass);
addRegisterClass(MVT::i64, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::v8i8, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::v4i16, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::v2i32, &Hexagon::DoubleRegsRegClass);
addRegisterClass(MVT::f32, &Hexagon::IntRegsRegClass);
addRegisterClass(MVT::f64, &Hexagon::DoubleRegsRegClass);
setOperationAction(ISD::ConstantFP, MVT::f32, Legal);
setOperationAction(ISD::ConstantFP, MVT::f64, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Legal);
setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
setOperationAction(ISD::INLINEASM, MVT::Other, Custom);
setOperationAction(ISD::INLINEASM_BR, MVT::Other, Custom);
setOperationAction(ISD::PREFETCH, MVT::Other, Custom);
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setOperationAction(ISD::EH_RETURN, MVT::Other, Custom);
setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom);
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::GlobalAddress, MVT::i8, Custom);
setOperationAction(ISD::BlockAddress, MVT::i32, Custom);
setOperationAction(ISD::SETCC, MVT::i8, Custom);
setOperationAction(ISD::SETCC, MVT::i16, Custom);
setOperationAction(ISD::SETCC, MVT::v4i8, Custom);
setOperationAction(ISD::SETCC, MVT::v2i16, Custom);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setOperationAction(ISD::VAARG, MVT::Other, Expand);
if (Subtarget.isEnvironmentMusl())
setOperationAction(ISD::VACOPY, MVT::Other, Custom);
else
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom);
if (EmitJumpTables)
setMinimumJumpTableEntries(MinimumJumpTables);
else
setMinimumJumpTableEntries(std::numeric_limits<unsigned>::max());
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
for (unsigned LegalIntOp :
{ISD::ABS, ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) {
setOperationAction(LegalIntOp, MVT::i32, Legal);
setOperationAction(LegalIntOp, MVT::i64, Legal);
}
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::UADDO, VT, Custom);
setOperationAction(ISD::USUBO, VT, Custom);
setOperationAction(ISD::SADDO, VT, Expand);
setOperationAction(ISD::SSUBO, VT, Expand);
setOperationAction(ISD::ADDCARRY, VT, Expand);
setOperationAction(ISD::SUBCARRY, VT, Expand);
}
setOperationAction(ISD::ADDCARRY, MVT::i64, Custom);
setOperationAction(ISD::SUBCARRY, MVT::i64, Custom);
setOperationAction(ISD::CTLZ, MVT::i8, Promote);
setOperationAction(ISD::CTLZ, MVT::i16, Promote);
setOperationAction(ISD::CTTZ, MVT::i8, Promote);
setOperationAction(ISD::CTTZ, MVT::i16, Promote);
setOperationAction(ISD::CTPOP, MVT::i8, Promote);
setOperationAction(ISD::CTPOP, MVT::i16, Promote);
setOperationAction(ISD::CTPOP, MVT::i32, Promote);
setOperationAction(ISD::CTPOP, MVT::i64, Legal);
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
setOperationAction(ISD::BSWAP, MVT::i32, Legal);
setOperationAction(ISD::BSWAP, MVT::i64, Legal);
setOperationAction(ISD::FSHL, MVT::i32, Legal);
setOperationAction(ISD::FSHL, MVT::i64, Legal);
setOperationAction(ISD::FSHR, MVT::i32, Legal);
setOperationAction(ISD::FSHR, MVT::i64, Legal);
for (unsigned IntExpOp :
{ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM,
ISD::SDIVREM, ISD::UDIVREM, ISD::ROTL, ISD::ROTR,
ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS,
ISD::SMUL_LOHI, ISD::UMUL_LOHI}) {
for (MVT VT : MVT::integer_valuetypes())
setOperationAction(IntExpOp, VT, Expand);
}
for (unsigned FPExpOp :
{ISD::FDIV, ISD::FREM, ISD::FSQRT, ISD::FSIN, ISD::FCOS, ISD::FSINCOS,
ISD::FPOW, ISD::FCOPYSIGN}) {
for (MVT VT : MVT::fp_valuetypes())
setOperationAction(FPExpOp, VT, Expand);
}
for (MVT VT : MVT::integer_valuetypes()) {
setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i32, Expand);
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i32, Expand);
setLoadExtAction(ISD::EXTLOAD, VT, MVT::i32, Expand);
}
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
for (MVT VT : MVT::fp_valuetypes())
setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand);
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::BR_CC, VT, Expand);
setOperationAction(ISD::SELECT_CC, VT, Expand);
}
for (MVT VT : MVT::fp_valuetypes()) {
setOperationAction(ISD::BR_CC, VT, Expand);
setOperationAction(ISD::SELECT_CC, VT, Expand);
}
setOperationAction(ISD::BR_CC, MVT::Other, Expand);
static const unsigned VectExpOps[] = {
ISD::ADD, ISD::SUB, ISD::MUL, ISD::SDIV, ISD::UDIV,
ISD::SREM, ISD::UREM, ISD::SDIVREM, ISD::UDIVREM, ISD::SADDO,
ISD::UADDO, ISD::SSUBO, ISD::USUBO, ISD::SMUL_LOHI, ISD::UMUL_LOHI,
ISD::AND, ISD::OR, ISD::XOR, ISD::ROTL, ISD::ROTR,
ISD::CTPOP, ISD::CTLZ, ISD::CTTZ,
ISD::FADD, ISD::FSUB, ISD::FMUL, ISD::FMA, ISD::FDIV,
ISD::FREM, ISD::FNEG, ISD::FABS, ISD::FSQRT, ISD::FSIN,
ISD::FCOS, ISD::FPOW, ISD::FLOG, ISD::FLOG2,
ISD::FLOG10, ISD::FEXP, ISD::FEXP2, ISD::FCEIL, ISD::FTRUNC,
ISD::FRINT, ISD::FNEARBYINT, ISD::FROUND, ISD::FFLOOR,
ISD::FMINNUM, ISD::FMAXNUM, ISD::FSINCOS,
ISD::BR_CC, ISD::SELECT_CC, ISD::ConstantPool,
ISD::BUILD_VECTOR, ISD::SCALAR_TO_VECTOR,
ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT,
ISD::EXTRACT_SUBVECTOR, ISD::INSERT_SUBVECTOR,
ISD::CONCAT_VECTORS, ISD::VECTOR_SHUFFLE,
ISD::SPLAT_VECTOR,
};
for (MVT VT : MVT::fixedlen_vector_valuetypes()) {
for (unsigned VectExpOp : VectExpOps)
setOperationAction(VectExpOp, VT, Expand);
for (MVT TargetVT : MVT::fixedlen_vector_valuetypes()) {
if (TargetVT == VT)
continue;
setLoadExtAction(ISD::EXTLOAD, TargetVT, VT, Expand);
setLoadExtAction(ISD::ZEXTLOAD, TargetVT, VT, Expand);
setLoadExtAction(ISD::SEXTLOAD, TargetVT, VT, Expand);
setTruncStoreAction(VT, TargetVT, Expand);
}
if (VT.getVectorElementType() != MVT::i32) {
MVT VT32 = MVT::getVectorVT(MVT::i32, VT.getSizeInBits()/32);
setOperationAction(ISD::SELECT, VT, Promote);
AddPromotedToType(ISD::SELECT, VT, VT32);
}
setOperationAction(ISD::SRA, VT, Custom);
setOperationAction(ISD::SHL, VT, Custom);
setOperationAction(ISD::SRL, VT, Custom);
}
setLoadExtAction(ISD::EXTLOAD, MVT::v2i16, MVT::v2i8, Legal);
setLoadExtAction(ISD::ZEXTLOAD, MVT::v2i16, MVT::v2i8, Legal);
setLoadExtAction(ISD::SEXTLOAD, MVT::v2i16, MVT::v2i8, Legal);
setLoadExtAction(ISD::EXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
setLoadExtAction(ISD::ZEXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
setLoadExtAction(ISD::SEXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i8, Legal);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i16, Legal);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i32, Legal);
for (MVT NativeVT : {MVT::v8i1, MVT::v4i1, MVT::v2i1, MVT::v4i8,
MVT::v8i8, MVT::v2i16, MVT::v4i16, MVT::v2i32}) {
setOperationAction(ISD::BUILD_VECTOR, NativeVT, Custom);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, NativeVT, Custom);
setOperationAction(ISD::INSERT_VECTOR_ELT, NativeVT, Custom);
setOperationAction(ISD::EXTRACT_SUBVECTOR, NativeVT, Custom);
setOperationAction(ISD::INSERT_SUBVECTOR, NativeVT, Custom);
setOperationAction(ISD::CONCAT_VECTORS, NativeVT, Custom);
setOperationAction(ISD::ADD, NativeVT, Legal);
setOperationAction(ISD::SUB, NativeVT, Legal);
setOperationAction(ISD::MUL, NativeVT, Legal);
setOperationAction(ISD::AND, NativeVT, Legal);
setOperationAction(ISD::OR, NativeVT, Legal);
setOperationAction(ISD::XOR, NativeVT, Legal);
if (NativeVT.getVectorElementType() != MVT::i1)
setOperationAction(ISD::SPLAT_VECTOR, NativeVT, Legal);
}
for (MVT VT : {MVT::v8i8, MVT::v4i16, MVT::v2i32}) {
setOperationAction(ISD::SMIN, VT, Legal);
setOperationAction(ISD::SMAX, VT, Legal);
setOperationAction(ISD::UMIN, VT, Legal);
setOperationAction(ISD::UMAX, VT, Legal);
}
for (MVT VT : {MVT::i16, MVT::i32, MVT::v4i8, MVT::i64, MVT::v8i8,
MVT::v2i16, MVT::v4i16, MVT::v2i32}) {
setOperationAction(ISD::LOAD, VT, Custom);
setOperationAction(ISD::STORE, VT, Custom);
}
for (MVT VT : {MVT::v2i1, MVT::v4i1, MVT::v8i1}) {
setOperationAction(ISD::LOAD, VT, Custom);
setOperationAction(ISD::STORE, VT, Custom);
}
for (MVT VT : {MVT::v2i16, MVT::v4i8, MVT::v8i8, MVT::v2i32, MVT::v4i16,
MVT::v2i32}) {
setCondCodeAction(ISD::SETNE, VT, Expand);
setCondCodeAction(ISD::SETLE, VT, Expand);
setCondCodeAction(ISD::SETGE, VT, Expand);
setCondCodeAction(ISD::SETLT, VT, Expand);
setCondCodeAction(ISD::SETULE, VT, Expand);
setCondCodeAction(ISD::SETUGE, VT, Expand);
setCondCodeAction(ISD::SETULT, VT, Expand);
}
setOperationAction(ISD::BITCAST, MVT::i8, Custom);
setOperationAction(ISD::SETCC, MVT::v2i16, Custom);
setOperationAction(ISD::VSELECT, MVT::v4i8, Custom);
setOperationAction(ISD::VSELECT, MVT::v2i16, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4i8, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4i16, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v8i8, Custom);
setOperationAction(ISD::FMA, MVT::f64, Expand);
setOperationAction(ISD::FADD, MVT::f64, Expand);
setOperationAction(ISD::FSUB, MVT::f64, Expand);
setOperationAction(ISD::FMUL, MVT::f64, Expand);
setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::i1, Promote);
setOperationAction(ISD::FP_TO_UINT, MVT::i8, Promote);
setOperationAction(ISD::FP_TO_UINT, MVT::i16, Promote);
setOperationAction(ISD::FP_TO_SINT, MVT::i1, Promote);
setOperationAction(ISD::FP_TO_SINT, MVT::i8, Promote);
setOperationAction(ISD::FP_TO_SINT, MVT::i16, Promote);
setOperationAction(ISD::UINT_TO_FP, MVT::i1, Promote);
setOperationAction(ISD::UINT_TO_FP, MVT::i8, Promote);
setOperationAction(ISD::UINT_TO_FP, MVT::i16, Promote);
setOperationAction(ISD::SINT_TO_FP, MVT::i1, Promote);
setOperationAction(ISD::SINT_TO_FP, MVT::i8, Promote);
setOperationAction(ISD::SINT_TO_FP, MVT::i16, Promote);
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
setTruncStoreAction(MVT::f32, MVT::f16, Expand);
setTruncStoreAction(MVT::f64, MVT::f16, Expand);
for (MVT VT : {MVT::i8, MVT::i16, MVT::i32, MVT::i64, MVT::f32, MVT::f64,
MVT::v2i16, MVT::v2i32, MVT::v4i8, MVT::v4i16, MVT::v8i8}) {
setIndexedLoadAction(ISD::POST_INC, VT, Legal);
setIndexedStoreAction(ISD::POST_INC, VT, Legal);
}
if (Subtarget.hasV60Ops()) {
setOperationAction(ISD::ROTL, MVT::i32, Legal);
setOperationAction(ISD::ROTL, MVT::i64, Legal);
setOperationAction(ISD::ROTR, MVT::i32, Legal);
setOperationAction(ISD::ROTR, MVT::i64, Legal);
}
if (Subtarget.hasV66Ops()) {
setOperationAction(ISD::FADD, MVT::f64, Legal);
setOperationAction(ISD::FSUB, MVT::f64, Legal);
}
if (Subtarget.hasV67Ops()) {
setOperationAction(ISD::FMINNUM, MVT::f64, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f64, Legal);
setOperationAction(ISD::FMUL, MVT::f64, Legal);
}
setTargetDAGCombine(ISD::VSELECT);
if (Subtarget.useHVXOps())
initializeHVXLowering();
computeRegisterProperties(&HRI);
bool FastMath = EnableFastMath;
setLibcallName(RTLIB::SDIV_I32, "__hexagon_divsi3");
setLibcallName(RTLIB::SDIV_I64, "__hexagon_divdi3");
setLibcallName(RTLIB::UDIV_I32, "__hexagon_udivsi3");
setLibcallName(RTLIB::UDIV_I64, "__hexagon_udivdi3");
setLibcallName(RTLIB::SREM_I32, "__hexagon_modsi3");
setLibcallName(RTLIB::SREM_I64, "__hexagon_moddi3");
setLibcallName(RTLIB::UREM_I32, "__hexagon_umodsi3");
setLibcallName(RTLIB::UREM_I64, "__hexagon_umoddi3");
setLibcallName(RTLIB::SINTTOFP_I128_F64, "__hexagon_floattidf");
setLibcallName(RTLIB::SINTTOFP_I128_F32, "__hexagon_floattisf");
setLibcallName(RTLIB::FPTOUINT_F32_I128, "__hexagon_fixunssfti");
setLibcallName(RTLIB::FPTOUINT_F64_I128, "__hexagon_fixunsdfti");
setLibcallName(RTLIB::FPTOSINT_F32_I128, "__hexagon_fixsfti");
setLibcallName(RTLIB::FPTOSINT_F64_I128, "__hexagon_fixdfti");
if (FastMath)
setLibcallName(RTLIB::SQRT_F64, "__hexagon_fast2_sqrtdf2");
if (FastMath) {
setLibcallName(RTLIB::ADD_F64, "__hexagon_fast_adddf3");
setLibcallName(RTLIB::SUB_F64, "__hexagon_fast_subdf3");
setLibcallName(RTLIB::MUL_F64, "__hexagon_fast_muldf3");
setLibcallName(RTLIB::DIV_F64, "__hexagon_fast_divdf3");
setLibcallName(RTLIB::DIV_F32, "__hexagon_fast_divsf3");
} else {
setLibcallName(RTLIB::ADD_F64, "__hexagon_adddf3");
setLibcallName(RTLIB::SUB_F64, "__hexagon_subdf3");
setLibcallName(RTLIB::MUL_F64, "__hexagon_muldf3");
setLibcallName(RTLIB::DIV_F64, "__hexagon_divdf3");
setLibcallName(RTLIB::DIV_F32, "__hexagon_divsf3");
}
if (FastMath)
setLibcallName(RTLIB::SQRT_F32, "__hexagon_fast2_sqrtf");
else
setLibcallName(RTLIB::SQRT_F32, "__hexagon_sqrtf");
setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
setLibcallName(RTLIB::FPROUND_F64_F16, "__truncdfhf2");
setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
setLibcallName(RTLIB::SHL_I128, nullptr);
setLibcallName(RTLIB::SRL_I128, nullptr);
setLibcallName(RTLIB::SRA_I128, nullptr);
}
const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch ((HexagonISD::NodeType)Opcode) {
case HexagonISD::ADDC: return "HexagonISD::ADDC";
case HexagonISD::SUBC: return "HexagonISD::SUBC";
case HexagonISD::ALLOCA: return "HexagonISD::ALLOCA";
case HexagonISD::AT_GOT: return "HexagonISD::AT_GOT";
case HexagonISD::AT_PCREL: return "HexagonISD::AT_PCREL";
case HexagonISD::BARRIER: return "HexagonISD::BARRIER";
case HexagonISD::CALL: return "HexagonISD::CALL";
case HexagonISD::CALLnr: return "HexagonISD::CALLnr";
case HexagonISD::CALLR: return "HexagonISD::CALLR";
case HexagonISD::COMBINE: return "HexagonISD::COMBINE";
case HexagonISD::CONST32_GP: return "HexagonISD::CONST32_GP";
case HexagonISD::CONST32: return "HexagonISD::CONST32";
case HexagonISD::CP: return "HexagonISD::CP";
case HexagonISD::DCFETCH: return "HexagonISD::DCFETCH";
case HexagonISD::EH_RETURN: return "HexagonISD::EH_RETURN";
case HexagonISD::TSTBIT: return "HexagonISD::TSTBIT";
case HexagonISD::EXTRACTU: return "HexagonISD::EXTRACTU";
case HexagonISD::INSERT: return "HexagonISD::INSERT";
case HexagonISD::JT: return "HexagonISD::JT";
case HexagonISD::RET_FLAG: return "HexagonISD::RET_FLAG";
case HexagonISD::TC_RETURN: return "HexagonISD::TC_RETURN";
case HexagonISD::VASL: return "HexagonISD::VASL";
case HexagonISD::VASR: return "HexagonISD::VASR";
case HexagonISD::VLSR: return "HexagonISD::VLSR";
case HexagonISD::VEXTRACTW: return "HexagonISD::VEXTRACTW";
case HexagonISD::VINSERTW0: return "HexagonISD::VINSERTW0";
case HexagonISD::VROR: return "HexagonISD::VROR";
case HexagonISD::READCYCLE: return "HexagonISD::READCYCLE";
case HexagonISD::PTRUE: return "HexagonISD::PTRUE";
case HexagonISD::PFALSE: return "HexagonISD::PFALSE";
case HexagonISD::D2P: return "HexagonISD::D2P";
case HexagonISD::P2D: return "HexagonISD::P2D";
case HexagonISD::V2Q: return "HexagonISD::V2Q";
case HexagonISD::Q2V: return "HexagonISD::Q2V";
case HexagonISD::QCAT: return "HexagonISD::QCAT";
case HexagonISD::QTRUE: return "HexagonISD::QTRUE";
case HexagonISD::QFALSE: return "HexagonISD::QFALSE";
case HexagonISD::TYPECAST: return "HexagonISD::TYPECAST";
case HexagonISD::VALIGN: return "HexagonISD::VALIGN";
case HexagonISD::VALIGNADDR: return "HexagonISD::VALIGNADDR";
case HexagonISD::VPACKL: return "HexagonISD::VPACKL";
case HexagonISD::VUNPACK: return "HexagonISD::VUNPACK";
case HexagonISD::VUNPACKU: return "HexagonISD::VUNPACKU";
case HexagonISD::ISEL: return "HexagonISD::ISEL";
case HexagonISD::OP_END: break;
}
return nullptr;
}
bool
HexagonTargetLowering::validateConstPtrAlignment(SDValue Ptr, Align NeedAlign,
const SDLoc &dl, SelectionDAG &DAG) const {
auto *CA = dyn_cast<ConstantSDNode>(Ptr);
if (!CA)
return true;
unsigned Addr = CA->getZExtValue();
Align HaveAlign =
Addr != 0 ? Align(1ull << countTrailingZeros(Addr)) : NeedAlign;
if (HaveAlign >= NeedAlign)
return true;
static int DK_MisalignedTrap = llvm::getNextAvailablePluginDiagnosticKind();
struct DiagnosticInfoMisalignedTrap : public DiagnosticInfo {
DiagnosticInfoMisalignedTrap(StringRef M)
: DiagnosticInfo(DK_MisalignedTrap, DS_Remark), Msg(M) {}
void print(DiagnosticPrinter &DP) const override {
DP << Msg;
}
static bool classof(const DiagnosticInfo *DI) {
return DI->getKind() == DK_MisalignedTrap;
}
StringRef Msg;
};
std::string ErrMsg;
raw_string_ostream O(ErrMsg);
O << "Misaligned constant address: " << format_hex(Addr, 10)
<< " has alignment " << HaveAlign.value()
<< ", but the memory access requires " << NeedAlign.value();
if (DebugLoc DL = dl.getDebugLoc())
DL.print(O << ", at ");
O << ". The instruction has been replaced with a trap.";
DAG.getContext()->diagnose(DiagnosticInfoMisalignedTrap(O.str()));
return false;
}
SDValue
HexagonTargetLowering::replaceMemWithUndef(SDValue Op, SelectionDAG &DAG)
const {
const SDLoc &dl(Op);
auto *LS = cast<LSBaseSDNode>(Op.getNode());
assert(!LS->isIndexed() && "Not expecting indexed ops on constant address");
SDValue Chain = LS->getChain();
SDValue Trap = DAG.getNode(ISD::TRAP, dl, MVT::Other, Chain);
if (LS->getOpcode() == ISD::LOAD)
return DAG.getMergeValues({DAG.getUNDEF(ty(Op)), Trap}, dl);
return Trap;
}
static bool isBrevLdIntrinsic(const Value *Inst) {
unsigned ID = cast<IntrinsicInst>(Inst)->getIntrinsicID();
return (ID == Intrinsic::hexagon_L2_loadrd_pbr ||
ID == Intrinsic::hexagon_L2_loadri_pbr ||
ID == Intrinsic::hexagon_L2_loadrh_pbr ||
ID == Intrinsic::hexagon_L2_loadruh_pbr ||
ID == Intrinsic::hexagon_L2_loadrb_pbr ||
ID == Intrinsic::hexagon_L2_loadrub_pbr);
}
static Value *getBrevLdObject(Value *V) {
if (Operator::getOpcode(V) == Instruction::ExtractValue ||
Operator::getOpcode(V) == Instruction::BitCast)
V = cast<Operator>(V)->getOperand(0);
else if (isa<IntrinsicInst>(V) && isBrevLdIntrinsic(V))
V = cast<Instruction>(V)->getOperand(0);
return V;
}
static Value *returnEdge(const PHINode *PN, Value *IntrBaseVal) {
const BasicBlock *Parent = PN->getParent();
int Idx = -1;
for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) {
BasicBlock *Blk = PN->getIncomingBlock(i);
if (Blk == Parent) {
Value *BackEdgeVal = PN->getIncomingValue(i);
Value *BaseVal;
do {
BaseVal = BackEdgeVal;
BackEdgeVal = getBrevLdObject(BackEdgeVal);
} while ((BaseVal != BackEdgeVal) && (IntrBaseVal != BackEdgeVal));
if (IntrBaseVal == BackEdgeVal)
continue;
Idx = i;
break;
} else Idx = i;
}
assert(Idx >= 0 && "Unexpected index to incoming argument in PHI");
return PN->getIncomingValue(Idx);
}
static Value *getUnderLyingObjectForBrevLdIntr(Value *V) {
Value *IntrBaseVal = V;
Value *BaseVal;
do {
BaseVal = V;
V = getBrevLdObject(V);
} while (BaseVal != V);
if (const PHINode *PN = dyn_cast<PHINode>(V))
return returnEdge(PN, IntrBaseVal);
else
return V;
}
bool HexagonTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
const CallInst &I,
MachineFunction &MF,
unsigned Intrinsic) const {
switch (Intrinsic) {
case Intrinsic::hexagon_L2_loadrd_pbr:
case Intrinsic::hexagon_L2_loadri_pbr:
case Intrinsic::hexagon_L2_loadrh_pbr:
case Intrinsic::hexagon_L2_loadruh_pbr:
case Intrinsic::hexagon_L2_loadrb_pbr:
case Intrinsic::hexagon_L2_loadrub_pbr: {
Info.opc = ISD::INTRINSIC_W_CHAIN;
auto &DL = I.getCalledFunction()->getParent()->getDataLayout();
auto &Cont = I.getCalledFunction()->getParent()->getContext();
Type *ElTy = I.getCalledFunction()->getReturnType()->getStructElementType(0);
Info.memVT = MVT::getVT(ElTy);
llvm::Value *BasePtrVal = I.getOperand(0);
Info.ptrVal = getUnderLyingObjectForBrevLdIntr(BasePtrVal);
Info.offset = 0;
Info.align = DL.getABITypeAlign(Info.memVT.getTypeForEVT(Cont));
Info.flags = MachineMemOperand::MOLoad;
return true;
}
case Intrinsic::hexagon_V6_vgathermw:
case Intrinsic::hexagon_V6_vgathermw_128B:
case Intrinsic::hexagon_V6_vgathermh:
case Intrinsic::hexagon_V6_vgathermh_128B:
case Intrinsic::hexagon_V6_vgathermhw:
case Intrinsic::hexagon_V6_vgathermhw_128B:
case Intrinsic::hexagon_V6_vgathermwq:
case Intrinsic::hexagon_V6_vgathermwq_128B:
case Intrinsic::hexagon_V6_vgathermhq:
case Intrinsic::hexagon_V6_vgathermhq_128B:
case Intrinsic::hexagon_V6_vgathermhwq:
case Intrinsic::hexagon_V6_vgathermhwq_128B: {
const Module &M = *I.getParent()->getParent()->getParent();
Info.opc = ISD::INTRINSIC_W_CHAIN;
Type *VecTy = I.getArgOperand(1)->getType();
Info.memVT = MVT::getVT(VecTy);
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
Info.align =
MaybeAlign(M.getDataLayout().getTypeAllocSizeInBits(VecTy) / 8);
Info.flags = MachineMemOperand::MOLoad |
MachineMemOperand::MOStore |
MachineMemOperand::MOVolatile;
return true;
}
default:
break;
}
return false;
}
bool HexagonTargetLowering::hasBitTest(SDValue X, SDValue Y) const {
return X.getValueType().isScalarInteger(); }
bool HexagonTargetLowering::isTruncateFree(Type *Ty1, Type *Ty2) const {
return isTruncateFree(EVT::getEVT(Ty1), EVT::getEVT(Ty2));
}
bool HexagonTargetLowering::isTruncateFree(EVT VT1, EVT VT2) const {
if (!VT1.isSimple() || !VT2.isSimple())
return false;
return VT1.getSimpleVT() == MVT::i64 && VT2.getSimpleVT() == MVT::i32;
}
bool HexagonTargetLowering::isFMAFasterThanFMulAndFAdd(
const MachineFunction &MF, EVT VT) const {
return isOperationLegalOrCustom(ISD::FMA, VT);
}
bool HexagonTargetLowering::shouldExpandBuildVectorWithShuffles(EVT VT,
unsigned DefinedValues) const {
return false;
}
bool HexagonTargetLowering::isShuffleMaskLegal(ArrayRef<int> Mask,
EVT VT) const {
return true;
}
TargetLoweringBase::LegalizeTypeAction
HexagonTargetLowering::getPreferredVectorAction(MVT VT) const {
unsigned VecLen = VT.getVectorMinNumElements();
MVT ElemTy = VT.getVectorElementType();
if (VecLen == 1 || VT.isScalableVector())
return TargetLoweringBase::TypeScalarizeVector;
if (Subtarget.useHVXOps()) {
unsigned Action = getPreferredHvxVectorAction(VT);
if (Action != ~0u)
return static_cast<TargetLoweringBase::LegalizeTypeAction>(Action);
}
if (ElemTy == MVT::i1)
return TargetLoweringBase::TypeWidenVector;
if (!isPowerOf2_32(VecLen))
return TargetLoweringBase::TypeWidenVector;
return TargetLoweringBase::TypeSplitVector;
}
std::pair<SDValue, int>
HexagonTargetLowering::getBaseAndOffset(SDValue Addr) const {
if (Addr.getOpcode() == ISD::ADD) {
SDValue Op1 = Addr.getOperand(1);
if (auto *CN = dyn_cast<const ConstantSDNode>(Op1.getNode()))
return { Addr.getOperand(0), CN->getSExtValue() };
}
return { Addr, 0 };
}
SDValue
HexagonTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG)
const {
const auto *SVN = cast<ShuffleVectorSDNode>(Op);
ArrayRef<int> AM = SVN->getMask();
assert(AM.size() <= 8 && "Unexpected shuffle mask");
unsigned VecLen = AM.size();
MVT VecTy = ty(Op);
assert(!Subtarget.isHVXVectorType(VecTy, true) &&
"HVX shuffles should be legal");
assert(VecTy.getSizeInBits() <= 64 && "Unexpected vector length");
SDValue Op0 = Op.getOperand(0);
SDValue Op1 = Op.getOperand(1);
const SDLoc &dl(Op);
if (ty(Op0) != VecTy || ty(Op1) != VecTy)
return SDValue();
SmallVector<int,8> Mask(AM.begin(), AM.end());
unsigned F = llvm::find_if(AM, [](int M) { return M >= 0; }) - AM.data();
if (F == AM.size())
return DAG.getUNDEF(VecTy);
if (AM[F] >= int(VecLen)) {
ShuffleVectorSDNode::commuteMask(Mask);
std::swap(Op0, Op1);
}
SmallVector<int,8> ByteMask;
unsigned ElemBytes = VecTy.getVectorElementType().getSizeInBits() / 8;
for (int M : Mask) {
if (M < 0) {
for (unsigned j = 0; j != ElemBytes; ++j)
ByteMask.push_back(-1);
} else {
for (unsigned j = 0; j != ElemBytes; ++j)
ByteMask.push_back(M*ElemBytes + j);
}
}
assert(ByteMask.size() <= 8);
uint64_t MaskIdx = 0;
uint64_t MaskUnd = 0;
for (unsigned i = 0, e = ByteMask.size(); i != e; ++i) {
unsigned S = 8*i;
uint64_t M = ByteMask[i] & 0xFF;
if (M == 0xFF)
MaskUnd |= M << S;
MaskIdx |= M << S;
}
if (ByteMask.size() == 4) {
if (MaskIdx == (0x03020100 | MaskUnd))
return Op0;
if (MaskIdx == (0x00010203 | MaskUnd)) {
SDValue T0 = DAG.getBitcast(MVT::i32, Op0);
SDValue T1 = DAG.getNode(ISD::BSWAP, dl, MVT::i32, T0);
return DAG.getBitcast(VecTy, T1);
}
SDValue Concat10 = DAG.getNode(HexagonISD::COMBINE, dl,
typeJoin({ty(Op1), ty(Op0)}), {Op1, Op0});
if (MaskIdx == (0x06040200 | MaskUnd))
return getInstr(Hexagon::S2_vtrunehb, dl, VecTy, {Concat10}, DAG);
if (MaskIdx == (0x07050301 | MaskUnd))
return getInstr(Hexagon::S2_vtrunohb, dl, VecTy, {Concat10}, DAG);
SDValue Concat01 = DAG.getNode(HexagonISD::COMBINE, dl,
typeJoin({ty(Op0), ty(Op1)}), {Op0, Op1});
if (MaskIdx == (0x02000604 | MaskUnd))
return getInstr(Hexagon::S2_vtrunehb, dl, VecTy, {Concat01}, DAG);
if (MaskIdx == (0x03010705 | MaskUnd))
return getInstr(Hexagon::S2_vtrunohb, dl, VecTy, {Concat01}, DAG);
}
if (ByteMask.size() == 8) {
if (MaskIdx == (0x0706050403020100ull | MaskUnd))
return Op0;
if (MaskIdx == (0x0001020304050607ull | MaskUnd)) {
SDValue T0 = DAG.getBitcast(MVT::i64, Op0);
SDValue T1 = DAG.getNode(ISD::BSWAP, dl, MVT::i64, T0);
return DAG.getBitcast(VecTy, T1);
}
if (MaskIdx == (0x0d0c050409080100ull | MaskUnd))
return getInstr(Hexagon::S2_shuffeh, dl, VecTy, {Op1, Op0}, DAG);
if (MaskIdx == (0x0f0e07060b0a0302ull | MaskUnd))
return getInstr(Hexagon::S2_shuffoh, dl, VecTy, {Op1, Op0}, DAG);
if (MaskIdx == (0x0d0c090805040100ull | MaskUnd))
return getInstr(Hexagon::S2_vtrunewh, dl, VecTy, {Op1, Op0}, DAG);
if (MaskIdx == (0x0f0e0b0a07060302ull | MaskUnd))
return getInstr(Hexagon::S2_vtrunowh, dl, VecTy, {Op1, Op0}, DAG);
if (MaskIdx == (0x0706030205040100ull | MaskUnd)) {
VectorPair P = opSplit(Op0, dl, DAG);
return getInstr(Hexagon::S2_packhl, dl, VecTy, {P.second, P.first}, DAG);
}
if (MaskIdx == (0x0e060c040a020800ull | MaskUnd))
return getInstr(Hexagon::S2_shuffeb, dl, VecTy, {Op1, Op0}, DAG);
if (MaskIdx == (0x0f070d050b030901ull | MaskUnd))
return getInstr(Hexagon::S2_shuffob, dl, VecTy, {Op1, Op0}, DAG);
}
return SDValue();
}
SDValue
HexagonTargetLowering::getVectorShiftByInt(SDValue Op, SelectionDAG &DAG)
const {
unsigned NewOpc;
switch (Op.getOpcode()) {
case ISD::SHL:
NewOpc = HexagonISD::VASL;
break;
case ISD::SRA:
NewOpc = HexagonISD::VASR;
break;
case ISD::SRL:
NewOpc = HexagonISD::VLSR;
break;
default:
llvm_unreachable("Unexpected shift opcode");
}
SDValue Op0 = Op.getOperand(0);
SDValue Op1 = Op.getOperand(1);
const SDLoc &dl(Op);
switch (Op1.getOpcode()) {
case ISD::BUILD_VECTOR:
if (SDValue S = cast<BuildVectorSDNode>(Op1)->getSplatValue())
return DAG.getNode(NewOpc, dl, ty(Op), Op0, S);
break;
case ISD::SPLAT_VECTOR:
return DAG.getNode(NewOpc, dl, ty(Op), Op0, Op1.getOperand(0));
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerVECTOR_SHIFT(SDValue Op, SelectionDAG &DAG) const {
return getVectorShiftByInt(Op, DAG);
}
SDValue
HexagonTargetLowering::LowerROTL(SDValue Op, SelectionDAG &DAG) const {
if (isa<ConstantSDNode>(Op.getOperand(1).getNode()))
return Op;
return SDValue();
}
SDValue
HexagonTargetLowering::LowerBITCAST(SDValue Op, SelectionDAG &DAG) const {
MVT ResTy = ty(Op);
SDValue InpV = Op.getOperand(0);
MVT InpTy = ty(InpV);
assert(ResTy.getSizeInBits() == InpTy.getSizeInBits());
const SDLoc &dl(Op);
if (InpTy == MVT::i8) {
if (ResTy == MVT::v8i1) {
SDValue Sc = DAG.getBitcast(tyScalar(InpTy), InpV);
SDValue Ext = DAG.getZExtOrTrunc(Sc, dl, MVT::i32);
return getInstr(Hexagon::C2_tfrrp, dl, ResTy, Ext, DAG);
}
return SDValue();
}
return Op;
}
bool
HexagonTargetLowering::getBuildVectorConstInts(ArrayRef<SDValue> Values,
MVT VecTy, SelectionDAG &DAG,
MutableArrayRef<ConstantInt*> Consts) const {
MVT ElemTy = VecTy.getVectorElementType();
unsigned ElemWidth = ElemTy.getSizeInBits();
IntegerType *IntTy = IntegerType::get(*DAG.getContext(), ElemWidth);
bool AllConst = true;
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
SDValue V = Values[i];
if (V.isUndef()) {
Consts[i] = ConstantInt::get(IntTy, 0);
continue;
}
if (auto *CN = dyn_cast<ConstantSDNode>(V.getNode())) {
const ConstantInt *CI = CN->getConstantIntValue();
Consts[i] = ConstantInt::get(IntTy, CI->getValue().getSExtValue());
} else if (auto *CN = dyn_cast<ConstantFPSDNode>(V.getNode())) {
const ConstantFP *CF = CN->getConstantFPValue();
APInt A = CF->getValueAPF().bitcastToAPInt();
Consts[i] = ConstantInt::get(IntTy, A.getZExtValue());
} else {
AllConst = false;
}
}
return AllConst;
}
SDValue
HexagonTargetLowering::buildVector32(ArrayRef<SDValue> Elem, const SDLoc &dl,
MVT VecTy, SelectionDAG &DAG) const {
MVT ElemTy = VecTy.getVectorElementType();
assert(VecTy.getVectorNumElements() == Elem.size());
SmallVector<ConstantInt*,4> Consts(Elem.size());
bool AllConst = getBuildVectorConstInts(Elem, VecTy, DAG, Consts);
unsigned First, Num = Elem.size();
for (First = 0; First != Num; ++First) {
if (!isUndef(Elem[First]))
break;
}
if (First == Num)
return DAG.getUNDEF(VecTy);
if (AllConst &&
llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
return getZero(dl, VecTy, DAG);
if (ElemTy == MVT::i16 || ElemTy == MVT::f16) {
assert(Elem.size() == 2);
if (AllConst) {
uint32_t V = (Consts[0]->getZExtValue() & 0xFFFF) |
Consts[1]->getZExtValue() << 16;
return DAG.getBitcast(VecTy, DAG.getConstant(V, dl, MVT::i32));
}
SDValue E0, E1;
if (ElemTy == MVT::f16) {
E0 = DAG.getZExtOrTrunc(DAG.getBitcast(MVT::i16, Elem[0]), dl, MVT::i32);
E1 = DAG.getZExtOrTrunc(DAG.getBitcast(MVT::i16, Elem[1]), dl, MVT::i32);
} else {
E0 = Elem[0];
E1 = Elem[1];
}
SDValue N = getInstr(Hexagon::A2_combine_ll, dl, MVT::i32, {E1, E0}, DAG);
return DAG.getBitcast(VecTy, N);
}
if (ElemTy == MVT::i8) {
if (AllConst) {
int32_t V = (Consts[0]->getZExtValue() & 0xFF) |
(Consts[1]->getZExtValue() & 0xFF) << 8 |
(Consts[2]->getZExtValue() & 0xFF) << 16 |
Consts[3]->getZExtValue() << 24;
return DAG.getBitcast(MVT::v4i8, DAG.getConstant(V, dl, MVT::i32));
}
bool IsSplat = true;
for (unsigned i = First+1; i != Num; ++i) {
if (Elem[i] == Elem[First] || isUndef(Elem[i]))
continue;
IsSplat = false;
break;
}
if (IsSplat) {
SDValue Ext = DAG.getZExtOrTrunc(Elem[First], dl, MVT::i32);
return DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Ext);
}
assert(Elem.size() == 4);
SDValue Vs[4];
for (unsigned i = 0; i != 4; ++i) {
Vs[i] = DAG.getZExtOrTrunc(Elem[i], dl, MVT::i32);
Vs[i] = DAG.getZeroExtendInReg(Vs[i], dl, MVT::i8);
}
SDValue S8 = DAG.getConstant(8, dl, MVT::i32);
SDValue T0 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[1], S8});
SDValue T1 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[3], S8});
SDValue B0 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[0], T0});
SDValue B1 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[2], T1});
SDValue R = getInstr(Hexagon::A2_combine_ll, dl, MVT::i32, {B1, B0}, DAG);
return DAG.getBitcast(MVT::v4i8, R);
}
#ifndef NDEBUG
dbgs() << "VecTy: " << EVT(VecTy).getEVTString() << '\n';
#endif
llvm_unreachable("Unexpected vector element type");
}
SDValue
HexagonTargetLowering::buildVector64(ArrayRef<SDValue> Elem, const SDLoc &dl,
MVT VecTy, SelectionDAG &DAG) const {
MVT ElemTy = VecTy.getVectorElementType();
assert(VecTy.getVectorNumElements() == Elem.size());
SmallVector<ConstantInt*,8> Consts(Elem.size());
bool AllConst = getBuildVectorConstInts(Elem, VecTy, DAG, Consts);
unsigned First, Num = Elem.size();
for (First = 0; First != Num; ++First) {
if (!isUndef(Elem[First]))
break;
}
if (First == Num)
return DAG.getUNDEF(VecTy);
if (AllConst &&
llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
return getZero(dl, VecTy, DAG);
if (ElemTy == MVT::i16 || ElemTy == MVT::f16) {
bool IsSplat = true;
for (unsigned i = First+1; i != Num; ++i) {
if (Elem[i] == Elem[First] || isUndef(Elem[i]))
continue;
IsSplat = false;
break;
}
if (IsSplat) {
SDValue S = ElemTy == MVT::f16 ? DAG.getBitcast(MVT::i16, Elem[First])
: Elem[First];
SDValue Ext = DAG.getZExtOrTrunc(S, dl, MVT::i32);
return DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Ext);
}
}
if (AllConst) {
uint64_t Val = 0;
unsigned W = ElemTy.getSizeInBits();
uint64_t Mask = (1ull << W) - 1;
for (unsigned i = 0; i != Num; ++i)
Val = (Val << W) | (Consts[Num-1-i]->getZExtValue() & Mask);
SDValue V0 = DAG.getConstant(Val, dl, MVT::i64);
return DAG.getBitcast(VecTy, V0);
}
MVT HalfTy = MVT::getVectorVT(ElemTy, Num/2);
SDValue L = (ElemTy == MVT::i32)
? Elem[0]
: buildVector32(Elem.take_front(Num/2), dl, HalfTy, DAG);
SDValue H = (ElemTy == MVT::i32)
? Elem[1]
: buildVector32(Elem.drop_front(Num/2), dl, HalfTy, DAG);
return DAG.getNode(HexagonISD::COMBINE, dl, VecTy, {H, L});
}
SDValue
HexagonTargetLowering::extractVector(SDValue VecV, SDValue IdxV,
const SDLoc &dl, MVT ValTy, MVT ResTy,
SelectionDAG &DAG) const {
MVT VecTy = ty(VecV);
assert(!ValTy.isVector() ||
VecTy.getVectorElementType() == ValTy.getVectorElementType());
unsigned VecWidth = VecTy.getSizeInBits();
unsigned ValWidth = ValTy.getSizeInBits();
unsigned ElemWidth = VecTy.getVectorElementType().getSizeInBits();
assert((VecWidth % ElemWidth) == 0);
auto *IdxN = dyn_cast<ConstantSDNode>(IdxV);
if (ElemWidth == 1) {
assert(VecWidth == VecTy.getVectorNumElements() &&
"Vector elements should equal vector width size");
assert(VecWidth == 8 || VecWidth == 4 || VecWidth == 2);
if (IdxN) {
if (IdxN->isZero() && ValTy.getSizeInBits() == 1)
return DAG.getNode(HexagonISD::TYPECAST, dl, MVT::i1, VecV);
}
if (ValWidth == 1) {
SDValue A0 = getInstr(Hexagon::C2_tfrpr, dl, MVT::i32, {VecV}, DAG);
SDValue M0 = DAG.getConstant(8 / VecWidth, dl, MVT::i32);
SDValue I0 = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, M0);
return DAG.getNode(HexagonISD::TSTBIT, dl, MVT::i1, A0, I0);
}
unsigned Scale = VecWidth / ValWidth;
assert(ty(IdxV) == MVT::i32);
unsigned VecRep = 8 / VecWidth;
SDValue S0 = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
DAG.getConstant(8*VecRep, dl, MVT::i32));
SDValue T0 = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, VecV);
SDValue T1 = DAG.getNode(ISD::SRL, dl, MVT::i64, T0, S0);
while (Scale > 1) {
T1 = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, T1);
T1 = expandPredicate(T1, dl, DAG);
Scale /= 2;
}
return DAG.getNode(HexagonISD::D2P, dl, ResTy, T1);
}
assert(VecWidth == 32 || VecWidth == 64);
MVT ScalarTy = tyScalar(VecTy);
VecV = DAG.getBitcast(ScalarTy, VecV);
SDValue WidthV = DAG.getConstant(ValWidth, dl, MVT::i32);
SDValue ExtV;
if (IdxN) {
unsigned Off = IdxN->getZExtValue() * ElemWidth;
if (VecWidth == 64 && ValWidth == 32) {
assert(Off == 0 || Off == 32);
unsigned SubIdx = Off == 0 ? Hexagon::isub_lo : Hexagon::isub_hi;
ExtV = DAG.getTargetExtractSubreg(SubIdx, dl, MVT::i32, VecV);
} else if (Off == 0 && (ValWidth % 8) == 0) {
ExtV = DAG.getZeroExtendInReg(VecV, dl, tyScalar(ValTy));
} else {
SDValue OffV = DAG.getConstant(Off, dl, MVT::i32);
ExtV = DAG.getNode(HexagonISD::EXTRACTU, dl, ScalarTy,
{VecV, WidthV, OffV});
}
} else {
if (ty(IdxV) != MVT::i32)
IdxV = DAG.getZExtOrTrunc(IdxV, dl, MVT::i32);
SDValue OffV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
DAG.getConstant(ElemWidth, dl, MVT::i32));
ExtV = DAG.getNode(HexagonISD::EXTRACTU, dl, ScalarTy,
{VecV, WidthV, OffV});
}
ExtV = DAG.getZExtOrTrunc(ExtV, dl, tyScalar(ResTy));
ExtV = DAG.getBitcast(ResTy, ExtV);
return ExtV;
}
SDValue
HexagonTargetLowering::insertVector(SDValue VecV, SDValue ValV, SDValue IdxV,
const SDLoc &dl, MVT ValTy,
SelectionDAG &DAG) const {
MVT VecTy = ty(VecV);
if (VecTy.getVectorElementType() == MVT::i1) {
MVT ValTy = ty(ValV);
assert(ValTy.getVectorElementType() == MVT::i1);
SDValue ValR = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, ValV);
unsigned VecLen = VecTy.getVectorNumElements();
unsigned Scale = VecLen / ValTy.getVectorNumElements();
assert(Scale > 1);
for (unsigned R = Scale; R > 1; R /= 2) {
ValR = contractPredicate(ValR, dl, DAG);
ValR = DAG.getNode(HexagonISD::COMBINE, dl, MVT::i64,
DAG.getUNDEF(MVT::i32), ValR);
}
ValR = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, ValR);
unsigned ValBytes = 64 / Scale;
SDValue Width = DAG.getConstant(ValBytes*8, dl, MVT::i32);
SDValue Idx = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
DAG.getConstant(8, dl, MVT::i32));
SDValue VecR = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, VecV);
SDValue Ins = DAG.getNode(HexagonISD::INSERT, dl, MVT::i32,
{VecR, ValR, Width, Idx});
return DAG.getNode(HexagonISD::D2P, dl, VecTy, Ins);
}
unsigned VecWidth = VecTy.getSizeInBits();
unsigned ValWidth = ValTy.getSizeInBits();
assert(VecWidth == 32 || VecWidth == 64);
assert((VecWidth % ValWidth) == 0);
MVT ScalarTy = MVT::getIntegerVT(VecWidth);
unsigned VW = ty(ValV).getSizeInBits();
ValV = DAG.getBitcast(MVT::getIntegerVT(VW), ValV);
VecV = DAG.getBitcast(ScalarTy, VecV);
if (VW != VecWidth)
ValV = DAG.getAnyExtOrTrunc(ValV, dl, ScalarTy);
SDValue WidthV = DAG.getConstant(ValWidth, dl, MVT::i32);
SDValue InsV;
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(IdxV)) {
unsigned W = C->getZExtValue() * ValWidth;
SDValue OffV = DAG.getConstant(W, dl, MVT::i32);
InsV = DAG.getNode(HexagonISD::INSERT, dl, ScalarTy,
{VecV, ValV, WidthV, OffV});
} else {
if (ty(IdxV) != MVT::i32)
IdxV = DAG.getZExtOrTrunc(IdxV, dl, MVT::i32);
SDValue OffV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, WidthV);
InsV = DAG.getNode(HexagonISD::INSERT, dl, ScalarTy,
{VecV, ValV, WidthV, OffV});
}
return DAG.getNode(ISD::BITCAST, dl, VecTy, InsV);
}
SDValue
HexagonTargetLowering::expandPredicate(SDValue Vec32, const SDLoc &dl,
SelectionDAG &DAG) const {
assert(ty(Vec32).getSizeInBits() == 32);
if (isUndef(Vec32))
return DAG.getUNDEF(MVT::i64);
return getInstr(Hexagon::S2_vsxtbh, dl, MVT::i64, {Vec32}, DAG);
}
SDValue
HexagonTargetLowering::contractPredicate(SDValue Vec64, const SDLoc &dl,
SelectionDAG &DAG) const {
assert(ty(Vec64).getSizeInBits() == 64);
if (isUndef(Vec64))
return DAG.getUNDEF(MVT::i32);
return getInstr(Hexagon::S2_vtrunehb, dl, MVT::i32, {Vec64}, DAG);
}
SDValue
HexagonTargetLowering::getZero(const SDLoc &dl, MVT Ty, SelectionDAG &DAG)
const {
if (Ty.isVector()) {
unsigned W = Ty.getSizeInBits();
if (W <= 64)
return DAG.getBitcast(Ty, DAG.getConstant(0, dl, MVT::getIntegerVT(W)));
return DAG.getNode(ISD::SPLAT_VECTOR, dl, Ty, getZero(dl, MVT::i32, DAG));
}
if (Ty.isInteger())
return DAG.getConstant(0, dl, Ty);
if (Ty.isFloatingPoint())
return DAG.getConstantFP(0.0, dl, Ty);
llvm_unreachable("Invalid type for zero");
}
SDValue
HexagonTargetLowering::appendUndef(SDValue Val, MVT ResTy, SelectionDAG &DAG)
const {
MVT ValTy = ty(Val);
assert(ValTy.getVectorElementType() == ResTy.getVectorElementType());
unsigned ValLen = ValTy.getVectorNumElements();
unsigned ResLen = ResTy.getVectorNumElements();
if (ValLen == ResLen)
return Val;
const SDLoc &dl(Val);
assert(ValLen < ResLen);
assert(ResLen % ValLen == 0);
SmallVector<SDValue, 4> Concats = {Val};
for (unsigned i = 1, e = ResLen / ValLen; i < e; ++i)
Concats.push_back(DAG.getUNDEF(ValTy));
return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResTy, Concats);
}
SDValue
HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
MVT VecTy = ty(Op);
unsigned BW = VecTy.getSizeInBits();
const SDLoc &dl(Op);
SmallVector<SDValue,8> Ops;
for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i)
Ops.push_back(Op.getOperand(i));
if (BW == 32)
return buildVector32(Ops, dl, VecTy, DAG);
if (BW == 64)
return buildVector64(Ops, dl, VecTy, DAG);
if (VecTy == MVT::v8i1 || VecTy == MVT::v4i1 || VecTy == MVT::v2i1) {
bool All0 = true, All1 = true;
for (SDValue P : Ops) {
auto *CN = dyn_cast<ConstantSDNode>(P.getNode());
if (CN == nullptr) {
All0 = All1 = false;
break;
}
uint32_t C = CN->getZExtValue();
All0 &= (C == 0);
All1 &= (C == 1);
}
if (All0)
return DAG.getNode(HexagonISD::PFALSE, dl, VecTy);
if (All1)
return DAG.getNode(HexagonISD::PTRUE, dl, VecTy);
SDValue Rs[8];
SDValue Z = getZero(dl, MVT::i32, DAG);
unsigned Rep = 8 / VecTy.getVectorNumElements();
for (unsigned i = 0; i != 8; ++i) {
SDValue S = DAG.getConstant(1ull << i, dl, MVT::i32);
Rs[i] = DAG.getSelect(dl, MVT::i32, Ops[i/Rep], S, Z);
}
for (ArrayRef<SDValue> A(Rs); A.size() != 1; A = A.drop_back(A.size()/2)) {
for (unsigned i = 0, e = A.size()/2; i != e; ++i)
Rs[i] = DAG.getNode(ISD::OR, dl, MVT::i32, Rs[2*i], Rs[2*i+1]);
}
return getInstr(Hexagon::C2_tfrrp, dl, VecTy, {Rs[0]}, DAG);
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerCONCAT_VECTORS(SDValue Op,
SelectionDAG &DAG) const {
MVT VecTy = ty(Op);
const SDLoc &dl(Op);
if (VecTy.getSizeInBits() == 64) {
assert(Op.getNumOperands() == 2);
return DAG.getNode(HexagonISD::COMBINE, dl, VecTy, Op.getOperand(1),
Op.getOperand(0));
}
MVT ElemTy = VecTy.getVectorElementType();
if (ElemTy == MVT::i1) {
assert(VecTy == MVT::v2i1 || VecTy == MVT::v4i1 || VecTy == MVT::v8i1);
MVT OpTy = ty(Op.getOperand(0));
unsigned Scale = VecTy.getVectorNumElements() / OpTy.getVectorNumElements();
assert(Scale == Op.getNumOperands() && Scale > 1);
SmallVector<SDValue,4> Words[2];
unsigned IdxW = 0;
for (SDValue P : Op.getNode()->op_values()) {
SDValue W = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, P);
for (unsigned R = Scale; R > 1; R /= 2) {
W = contractPredicate(W, dl, DAG);
W = DAG.getNode(HexagonISD::COMBINE, dl, MVT::i64,
DAG.getUNDEF(MVT::i32), W);
}
W = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, W);
Words[IdxW].push_back(W);
}
while (Scale > 2) {
SDValue WidthV = DAG.getConstant(64 / Scale, dl, MVT::i32);
Words[IdxW ^ 1].clear();
for (unsigned i = 0, e = Words[IdxW].size(); i != e; i += 2) {
SDValue W0 = Words[IdxW][i], W1 = Words[IdxW][i+1];
SDValue T = DAG.getNode(HexagonISD::INSERT, dl, MVT::i32,
{W0, W1, WidthV, WidthV});
Words[IdxW ^ 1].push_back(T);
}
IdxW ^= 1;
Scale /= 2;
}
assert(Scale == 2 && Words[IdxW].size() == 2);
SDValue WW = DAG.getNode(HexagonISD::COMBINE, dl, MVT::i64,
Words[IdxW][1], Words[IdxW][0]);
return DAG.getNode(HexagonISD::D2P, dl, VecTy, WW);
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
SelectionDAG &DAG) const {
SDValue Vec = Op.getOperand(0);
MVT ElemTy = ty(Vec).getVectorElementType();
return extractVector(Vec, Op.getOperand(1), SDLoc(Op), ElemTy, ty(Op), DAG);
}
SDValue
HexagonTargetLowering::LowerEXTRACT_SUBVECTOR(SDValue Op,
SelectionDAG &DAG) const {
return extractVector(Op.getOperand(0), Op.getOperand(1), SDLoc(Op),
ty(Op), ty(Op), DAG);
}
SDValue
HexagonTargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op,
SelectionDAG &DAG) const {
return insertVector(Op.getOperand(0), Op.getOperand(1), Op.getOperand(2),
SDLoc(Op), ty(Op).getVectorElementType(), DAG);
}
SDValue
HexagonTargetLowering::LowerINSERT_SUBVECTOR(SDValue Op,
SelectionDAG &DAG) const {
SDValue ValV = Op.getOperand(1);
return insertVector(Op.getOperand(0), ValV, Op.getOperand(2),
SDLoc(Op), ty(ValV), DAG);
}
bool
HexagonTargetLowering::allowTruncateForTailCall(Type *Ty1, Type *Ty2) const {
if (!Ty1->isIntegerTy() || !Ty2->isIntegerTy())
return false;
return Ty1->getPrimitiveSizeInBits() <= 32;
}
SDValue
HexagonTargetLowering::LowerLoad(SDValue Op, SelectionDAG &DAG) const {
MVT Ty = ty(Op);
const SDLoc &dl(Op);
LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
bool DoCast = (Ty == MVT::v2i1 || Ty == MVT::v4i1 || Ty == MVT::v8i1);
if (DoCast) {
SDValue NL = DAG.getLoad(
LN->getAddressingMode(), LN->getExtensionType(), MVT::i1, dl,
LN->getChain(), LN->getBasePtr(), LN->getOffset(), LN->getPointerInfo(),
MVT::i1, LN->getAlign(), LN->getMemOperand()->getFlags(),
LN->getAAInfo(), LN->getRanges());
LN = cast<LoadSDNode>(NL.getNode());
}
Align ClaimAlign = LN->getAlign();
if (!validateConstPtrAlignment(LN->getBasePtr(), ClaimAlign, dl, DAG))
return replaceMemWithUndef(Op, DAG);
SDValue LU = LowerUnalignedLoad(SDValue(LN, 0), DAG);
if (DoCast) {
SDValue TC = DAG.getNode(HexagonISD::TYPECAST, dl, Ty, LU);
SDValue Ch = cast<LoadSDNode>(LU.getNode())->getChain();
return DAG.getMergeValues({TC, Ch}, dl);
}
return LU;
}
SDValue
HexagonTargetLowering::LowerStore(SDValue Op, SelectionDAG &DAG) const {
const SDLoc &dl(Op);
StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
SDValue Val = SN->getValue();
MVT Ty = ty(Val);
bool DoCast = (Ty == MVT::v2i1 || Ty == MVT::v4i1 || Ty == MVT::v8i1);
if (DoCast) {
SDValue TC = DAG.getNode(HexagonISD::TYPECAST, dl, MVT::i1, Val);
SDValue NS = DAG.getStore(SN->getChain(), dl, TC, SN->getBasePtr(),
SN->getMemOperand());
if (SN->isIndexed()) {
NS = DAG.getIndexedStore(NS, dl, SN->getBasePtr(), SN->getOffset(),
SN->getAddressingMode());
}
SN = cast<StoreSDNode>(NS.getNode());
}
Align ClaimAlign = SN->getAlign();
if (!validateConstPtrAlignment(SN->getBasePtr(), ClaimAlign, dl, DAG))
return replaceMemWithUndef(Op, DAG);
MVT StoreTy = SN->getMemoryVT().getSimpleVT();
Align NeedAlign = Subtarget.getTypeAlignment(StoreTy);
if (ClaimAlign < NeedAlign)
return expandUnalignedStore(SN, DAG);
return SDValue(SN, 0);
}
SDValue
HexagonTargetLowering::LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG)
const {
LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
MVT LoadTy = ty(Op);
unsigned NeedAlign = Subtarget.getTypeAlignment(LoadTy).value();
unsigned HaveAlign = LN->getAlign().value();
if (HaveAlign >= NeedAlign)
return Op;
const SDLoc &dl(Op);
const DataLayout &DL = DAG.getDataLayout();
LLVMContext &Ctx = *DAG.getContext();
bool DoDefault = false;
if (!LN->isUnindexed())
DoDefault = true;
if (!AlignLoads) {
if (allowsMemoryAccessForAlignment(Ctx, DL, LN->getMemoryVT(),
*LN->getMemOperand()))
return Op;
DoDefault = true;
}
if (!DoDefault && (2 * HaveAlign) == NeedAlign) {
MVT PartTy = HaveAlign <= 8 ? MVT::getIntegerVT(8 * HaveAlign)
: MVT::getVectorVT(MVT::i8, HaveAlign);
DoDefault =
allowsMemoryAccessForAlignment(Ctx, DL, PartTy, *LN->getMemOperand());
}
if (DoDefault) {
std::pair<SDValue, SDValue> P = expandUnalignedLoad(LN, DAG);
return DAG.getMergeValues({P.first, P.second}, dl);
}
assert(LoadTy.getSizeInBits() == 8*NeedAlign);
unsigned LoadLen = NeedAlign;
SDValue Base = LN->getBasePtr();
SDValue Chain = LN->getChain();
auto BO = getBaseAndOffset(Base);
unsigned BaseOpc = BO.first.getOpcode();
if (BaseOpc == HexagonISD::VALIGNADDR && BO.second % LoadLen == 0)
return Op;
if (BO.second % LoadLen != 0) {
BO.first = DAG.getNode(ISD::ADD, dl, MVT::i32, BO.first,
DAG.getConstant(BO.second % LoadLen, dl, MVT::i32));
BO.second -= BO.second % LoadLen;
}
SDValue BaseNoOff = (BaseOpc != HexagonISD::VALIGNADDR)
? DAG.getNode(HexagonISD::VALIGNADDR, dl, MVT::i32, BO.first,
DAG.getConstant(NeedAlign, dl, MVT::i32))
: BO.first;
SDValue Base0 =
DAG.getMemBasePlusOffset(BaseNoOff, TypeSize::Fixed(BO.second), dl);
SDValue Base1 = DAG.getMemBasePlusOffset(
BaseNoOff, TypeSize::Fixed(BO.second + LoadLen), dl);
MachineMemOperand *WideMMO = nullptr;
if (MachineMemOperand *MMO = LN->getMemOperand()) {
MachineFunction &MF = DAG.getMachineFunction();
WideMMO = MF.getMachineMemOperand(
MMO->getPointerInfo(), MMO->getFlags(), 2 * LoadLen, Align(LoadLen),
MMO->getAAInfo(), MMO->getRanges(), MMO->getSyncScopeID(),
MMO->getSuccessOrdering(), MMO->getFailureOrdering());
}
SDValue Load0 = DAG.getLoad(LoadTy, dl, Chain, Base0, WideMMO);
SDValue Load1 = DAG.getLoad(LoadTy, dl, Chain, Base1, WideMMO);
SDValue Aligned = DAG.getNode(HexagonISD::VALIGN, dl, LoadTy,
{Load1, Load0, BaseNoOff.getOperand(0)});
SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
Load0.getValue(1), Load1.getValue(1));
SDValue M = DAG.getMergeValues({Aligned, NewChain}, dl);
return M;
}
SDValue
HexagonTargetLowering::LowerUAddSubO(SDValue Op, SelectionDAG &DAG) const {
SDValue X = Op.getOperand(0), Y = Op.getOperand(1);
auto *CY = dyn_cast<ConstantSDNode>(Y);
if (!CY)
return SDValue();
const SDLoc &dl(Op);
SDVTList VTs = Op.getNode()->getVTList();
assert(VTs.NumVTs == 2);
assert(VTs.VTs[1] == MVT::i1);
unsigned Opc = Op.getOpcode();
if (CY) {
uint32_t VY = CY->getZExtValue();
assert(VY != 0 && "This should have been folded");
if (VY != 1)
return SDValue();
if (Opc == ISD::UADDO) {
SDValue Op = DAG.getNode(ISD::ADD, dl, VTs.VTs[0], {X, Y});
SDValue Ov = DAG.getSetCC(dl, MVT::i1, Op, getZero(dl, ty(Op), DAG),
ISD::SETEQ);
return DAG.getMergeValues({Op, Ov}, dl);
}
if (Opc == ISD::USUBO) {
SDValue Op = DAG.getNode(ISD::SUB, dl, VTs.VTs[0], {X, Y});
SDValue Ov = DAG.getSetCC(dl, MVT::i1, Op,
DAG.getConstant(-1, dl, ty(Op)), ISD::SETEQ);
return DAG.getMergeValues({Op, Ov}, dl);
}
}
return SDValue();
}
SDValue
HexagonTargetLowering::LowerAddSubCarry(SDValue Op, SelectionDAG &DAG) const {
const SDLoc &dl(Op);
unsigned Opc = Op.getOpcode();
SDValue X = Op.getOperand(0), Y = Op.getOperand(1), C = Op.getOperand(2);
if (Opc == ISD::ADDCARRY)
return DAG.getNode(HexagonISD::ADDC, dl, Op.getNode()->getVTList(),
{ X, Y, C });
EVT CarryTy = C.getValueType();
SDValue SubC = DAG.getNode(HexagonISD::SUBC, dl, Op.getNode()->getVTList(),
{ X, Y, DAG.getLogicalNOT(dl, C, CarryTy) });
SDValue Out[] = { SubC.getValue(0),
DAG.getLogicalNOT(dl, SubC.getValue(1), CarryTy) };
return DAG.getMergeValues(Out, dl);
}
SDValue
HexagonTargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDValue Offset = Op.getOperand(1);
SDValue Handler = Op.getOperand(2);
SDLoc dl(Op);
auto PtrVT = getPointerTy(DAG.getDataLayout());
HexagonMachineFunctionInfo *FuncInfo =
DAG.getMachineFunction().getInfo<HexagonMachineFunctionInfo>();
FuncInfo->setHasEHReturn();
unsigned OffsetReg = Hexagon::R28;
SDValue StoreAddr =
DAG.getNode(ISD::ADD, dl, PtrVT, DAG.getRegister(Hexagon::R30, PtrVT),
DAG.getIntPtrConstant(4, dl));
Chain = DAG.getStore(Chain, dl, Handler, StoreAddr, MachinePointerInfo());
Chain = DAG.getCopyToReg(Chain, dl, OffsetReg, Offset);
return DAG.getNode(HexagonISD::EH_RETURN, dl, MVT::Other, Chain);
}
SDValue
HexagonTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
unsigned Opc = Op.getOpcode();
if (Opc == ISD::INLINEASM || Opc == ISD::INLINEASM_BR)
return LowerINLINEASM(Op, DAG);
if (isHvxOperation(Op.getNode(), DAG)) {
if (SDValue V = LowerHvxOperation(Op, DAG))
return V;
}
switch (Opc) {
default:
#ifndef NDEBUG
Op.getNode()->dumpr(&DAG);
if (Opc > HexagonISD::OP_BEGIN && Opc < HexagonISD::OP_END)
errs() << "Error: check for a non-legal type in this operation\n";
#endif
llvm_unreachable("Should not custom lower this!");
case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG);
case ISD::INSERT_SUBVECTOR: return LowerINSERT_SUBVECTOR(Op, DAG);
case ISD::INSERT_VECTOR_ELT: return LowerINSERT_VECTOR_ELT(Op, DAG);
case ISD::EXTRACT_SUBVECTOR: return LowerEXTRACT_SUBVECTOR(Op, DAG);
case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG);
case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG);
case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG);
case ISD::BITCAST: return LowerBITCAST(Op, DAG);
case ISD::LOAD: return LowerLoad(Op, DAG);
case ISD::STORE: return LowerStore(Op, DAG);
case ISD::UADDO:
case ISD::USUBO: return LowerUAddSubO(Op, DAG);
case ISD::ADDCARRY:
case ISD::SUBCARRY: return LowerAddSubCarry(Op, DAG);
case ISD::SRA:
case ISD::SHL:
case ISD::SRL: return LowerVECTOR_SHIFT(Op, DAG);
case ISD::ROTL: return LowerROTL(Op, DAG);
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG);
case ISD::GlobalAddress: return LowerGLOBALADDRESS(Op, DAG);
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG);
case ISD::VACOPY: return LowerVACOPY(Op, DAG);
case ISD::VASTART: return LowerVASTART(Op, DAG);
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::SETCC: return LowerSETCC(Op, DAG);
case ISD::VSELECT: return LowerVSELECT(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG);
case ISD::PREFETCH: return LowerPREFETCH(Op, DAG);
case ISD::READCYCLECOUNTER: return LowerREADCYCLECOUNTER(Op, DAG);
break;
}
return SDValue();
}
void
HexagonTargetLowering::LowerOperationWrapper(SDNode *N,
SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const {
if (isHvxOperation(N, DAG)) {
LowerHvxOperationWrapper(N, Results, DAG);
if (!Results.empty())
return;
}
if (N->getOpcode() != ISD::STORE)
return TargetLowering::LowerOperationWrapper(N, Results, DAG);
}
void
HexagonTargetLowering::ReplaceNodeResults(SDNode *N,
SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const {
if (isHvxOperation(N, DAG)) {
ReplaceHvxNodeResults(N, Results, DAG);
if (!Results.empty())
return;
}
const SDLoc &dl(N);
switch (N->getOpcode()) {
case ISD::SRL:
case ISD::SRA:
case ISD::SHL:
return;
case ISD::BITCAST:
if (N->getValueType(0) == MVT::i8) {
if (N->getOperand(0).getValueType() == MVT::v8i1) {
SDValue P = getInstr(Hexagon::C2_tfrpr, dl, MVT::i32,
N->getOperand(0), DAG);
SDValue T = DAG.getAnyExtOrTrunc(P, dl, MVT::i8);
Results.push_back(T);
}
}
break;
}
}
SDValue
HexagonTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
const {
if (isHvxOperation(N, DCI.DAG)) {
if (SDValue V = PerformHvxDAGCombine(N, DCI))
return V;
return SDValue();
}
if (DCI.isBeforeLegalizeOps())
return SDValue();
SDValue Op(N, 0);
const SDLoc &dl(Op);
unsigned Opc = Op.getOpcode();
if (Opc == HexagonISD::P2D) {
SDValue P = Op.getOperand(0);
switch (P.getOpcode()) {
case HexagonISD::PTRUE:
return DCI.DAG.getConstant(-1, dl, ty(Op));
case HexagonISD::PFALSE:
return getZero(dl, ty(Op), DCI.DAG);
default:
break;
}
} else if (Opc == ISD::VSELECT) {
SDValue Cond = Op.getOperand(0);
if (Cond->getOpcode() == ISD::XOR) {
SDValue C0 = Cond.getOperand(0), C1 = Cond.getOperand(1);
if (C1->getOpcode() == HexagonISD::PTRUE) {
SDValue VSel = DCI.DAG.getNode(ISD::VSELECT, dl, ty(Op), C0,
Op.getOperand(2), Op.getOperand(1));
return VSel;
}
}
}
return SDValue();
}
SDValue
HexagonTargetLowering::getPICJumpTableRelocBase(SDValue Table,
SelectionDAG &DAG) const {
int Idx = cast<JumpTableSDNode>(Table)->getIndex();
EVT VT = Table.getValueType();
SDValue T = DAG.getTargetJumpTable(Idx, VT, HexagonII::MO_PCREL);
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Table), VT, T);
}
TargetLowering::ConstraintType
HexagonTargetLowering::getConstraintType(StringRef Constraint) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'q':
case 'v':
if (Subtarget.useHVXOps())
return C_RegisterClass;
break;
case 'a':
return C_RegisterClass;
default:
break;
}
}
return TargetLowering::getConstraintType(Constraint);
}
std::pair<unsigned, const TargetRegisterClass*>
HexagonTargetLowering::getRegForInlineAsmConstraint(
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'r': switch (VT.SimpleTy) {
default:
return {0u, nullptr};
case MVT::i1:
case MVT::i8:
case MVT::i16:
case MVT::i32:
case MVT::f32:
return {0u, &Hexagon::IntRegsRegClass};
case MVT::i64:
case MVT::f64:
return {0u, &Hexagon::DoubleRegsRegClass};
}
break;
case 'a': if (VT != MVT::i32)
return {0u, nullptr};
return {0u, &Hexagon::ModRegsRegClass};
case 'q': switch (VT.getSizeInBits()) {
default:
return {0u, nullptr};
case 64:
case 128:
return {0u, &Hexagon::HvxQRRegClass};
}
break;
case 'v': switch (VT.getSizeInBits()) {
default:
return {0u, nullptr};
case 512:
return {0u, &Hexagon::HvxVRRegClass};
case 1024:
if (Subtarget.hasV60Ops() && Subtarget.useHVX128BOps())
return {0u, &Hexagon::HvxVRRegClass};
return {0u, &Hexagon::HvxWRRegClass};
case 2048:
return {0u, &Hexagon::HvxWRRegClass};
}
break;
default:
return {0u, nullptr};
}
}
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
}
bool HexagonTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const {
return true;
}
bool HexagonTargetLowering::isLegalAddressingMode(const DataLayout &DL,
const AddrMode &AM, Type *Ty,
unsigned AS, Instruction *I) const {
if (Ty->isSized()) {
Align A = DL.getABITypeAlign(Ty);
if (!isAligned(A, AM.BaseOffs))
return false;
if (!isInt<11>(AM.BaseOffs >> Log2(A)))
return false;
}
if (AM.BaseGV)
return false;
int Scale = AM.Scale;
if (Scale < 0)
Scale = -Scale;
switch (Scale) {
case 0: break;
default: return false;
}
return true;
}
bool HexagonTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA)
const {
return HTM.getRelocationModel() == Reloc::Static;
}
bool HexagonTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
return Imm >= -512 && Imm <= 511;
}
bool HexagonTargetLowering::IsEligibleForTailCallOptimization(
SDValue Callee,
CallingConv::ID CalleeCC,
bool IsVarArg,
bool IsCalleeStructRet,
bool IsCallerStructRet,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SmallVectorImpl<ISD::InputArg> &Ins,
SelectionDAG& DAG) const {
const Function &CallerF = DAG.getMachineFunction().getFunction();
CallingConv::ID CallerCC = CallerF.getCallingConv();
bool CCMatch = CallerCC == CalleeCC;
if (!isa<GlobalAddressSDNode>(Callee) &&
!isa<ExternalSymbolSDNode>(Callee)) {
return false;
}
if (!CCMatch) {
bool R = (CallerCC == CallingConv::C || CallerCC == CallingConv::Fast);
bool E = (CalleeCC == CallingConv::C || CalleeCC == CallingConv::Fast);
if (!R || !E)
return false;
}
if (IsVarArg)
return false;
if (IsCalleeStructRet || IsCallerStructRet)
return false;
return true;
}
EVT HexagonTargetLowering::getOptimalMemOpType(
const MemOp &Op, const AttributeList &FuncAttributes) const {
if (Op.size() >= 8 && Op.isAligned(Align(8)))
return MVT::i64;
if (Op.size() >= 4 && Op.isAligned(Align(4)))
return MVT::i32;
if (Op.size() >= 2 && Op.isAligned(Align(2)))
return MVT::i16;
return MVT::Other;
}
bool HexagonTargetLowering::allowsMemoryAccess(
LLVMContext &Context, const DataLayout &DL, EVT VT, unsigned AddrSpace,
Align Alignment, MachineMemOperand::Flags Flags, bool *Fast) const {
MVT SVT = VT.getSimpleVT();
if (Subtarget.isHVXVectorType(SVT, true))
return allowsHvxMemoryAccess(SVT, Flags, Fast);
return TargetLoweringBase::allowsMemoryAccess(
Context, DL, VT, AddrSpace, Alignment, Flags, Fast);
}
bool HexagonTargetLowering::allowsMisalignedMemoryAccesses(
EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
bool *Fast) const {
MVT SVT = VT.getSimpleVT();
if (Subtarget.isHVXVectorType(SVT, true))
return allowsHvxMisalignedMemoryAccesses(SVT, Flags, Fast);
if (Fast)
*Fast = false;
return false;
}
std::pair<const TargetRegisterClass*, uint8_t>
HexagonTargetLowering::findRepresentativeClass(const TargetRegisterInfo *TRI,
MVT VT) const {
if (Subtarget.isHVXVectorType(VT, true)) {
unsigned BitWidth = VT.getSizeInBits();
unsigned VecWidth = Subtarget.getVectorLength() * 8;
if (VT.getVectorElementType() == MVT::i1)
return std::make_pair(&Hexagon::HvxQRRegClass, 1);
if (BitWidth == VecWidth)
return std::make_pair(&Hexagon::HvxVRRegClass, 1);
assert(BitWidth == 2 * VecWidth);
return std::make_pair(&Hexagon::HvxWRRegClass, 1);
}
return TargetLowering::findRepresentativeClass(TRI, VT);
}
bool HexagonTargetLowering::shouldReduceLoadWidth(SDNode *Load,
ISD::LoadExtType ExtTy, EVT NewVT) const {
if (!TargetLoweringBase::shouldReduceLoadWidth(Load, ExtTy, NewVT))
return false;
auto *L = cast<LoadSDNode>(Load);
std::pair<SDValue,int> BO = getBaseAndOffset(L->getBasePtr());
if (BO.first.getOpcode() == HexagonISD::CONST32_GP)
return false;
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(BO.first)) {
auto &HTM = static_cast<const HexagonTargetMachine&>(getTargetMachine());
const auto *GO = dyn_cast_or_null<const GlobalObject>(GA->getGlobal());
return !GO || !HTM.getObjFileLowering()->isGlobalInSmallSection(GO, HTM);
}
return true;
}
Value *HexagonTargetLowering::emitLoadLinked(IRBuilderBase &Builder,
Type *ValueTy, Value *Addr,
AtomicOrdering Ord) const {
BasicBlock *BB = Builder.GetInsertBlock();
Module *M = BB->getParent()->getParent();
unsigned SZ = ValueTy->getPrimitiveSizeInBits();
assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic loads supported");
Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_L2_loadw_locked
: Intrinsic::hexagon_L4_loadd_locked;
Function *Fn = Intrinsic::getDeclaration(M, IntID);
auto PtrTy = cast<PointerType>(Addr->getType());
PointerType *NewPtrTy =
Builder.getIntNTy(SZ)->getPointerTo(PtrTy->getAddressSpace());
Addr = Builder.CreateBitCast(Addr, NewPtrTy);
Value *Call = Builder.CreateCall(Fn, Addr, "larx");
return Builder.CreateBitCast(Call, ValueTy);
}
Value *HexagonTargetLowering::emitStoreConditional(IRBuilderBase &Builder,
Value *Val, Value *Addr,
AtomicOrdering Ord) const {
BasicBlock *BB = Builder.GetInsertBlock();
Module *M = BB->getParent()->getParent();
Type *Ty = Val->getType();
unsigned SZ = Ty->getPrimitiveSizeInBits();
Type *CastTy = Builder.getIntNTy(SZ);
assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic stores supported");
Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_S2_storew_locked
: Intrinsic::hexagon_S4_stored_locked;
Function *Fn = Intrinsic::getDeclaration(M, IntID);
unsigned AS = Addr->getType()->getPointerAddressSpace();
Addr = Builder.CreateBitCast(Addr, CastTy->getPointerTo(AS));
Val = Builder.CreateBitCast(Val, CastTy);
Value *Call = Builder.CreateCall(Fn, {Addr, Val}, "stcx");
Value *Cmp = Builder.CreateICmpEQ(Call, Builder.getInt32(0), "");
Value *Ext = Builder.CreateZExt(Cmp, Type::getInt32Ty(M->getContext()));
return Ext;
}
TargetLowering::AtomicExpansionKind
HexagonTargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const {
return LI->getType()->getPrimitiveSizeInBits() > 64
? AtomicExpansionKind::LLOnly
: AtomicExpansionKind::None;
}
TargetLowering::AtomicExpansionKind
HexagonTargetLowering::shouldExpandAtomicStoreInIR(StoreInst *SI) const {
return SI->getValueOperand()->getType()->getPrimitiveSizeInBits() > 64
? AtomicExpansionKind::Expand
: AtomicExpansionKind::None;
}
TargetLowering::AtomicExpansionKind
HexagonTargetLowering::shouldExpandAtomicCmpXchgInIR(
AtomicCmpXchgInst *AI) const {
return AtomicExpansionKind::LLSC;
}