aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp')
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp508
1 files changed, 308 insertions, 200 deletions
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
index a6ac4e3df745..efb4c2eb0fc3 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
@@ -64,51 +64,6 @@ FunctionPass *createHexagonISelDag(HexagonTargetMachine &TM,
}
}
-// Intrinsics that return a a predicate.
-static bool doesIntrinsicReturnPredicate(unsigned ID) {
- switch (ID) {
- default:
- return false;
- case Intrinsic::hexagon_C2_cmpeq:
- case Intrinsic::hexagon_C2_cmpgt:
- case Intrinsic::hexagon_C2_cmpgtu:
- case Intrinsic::hexagon_C2_cmpgtup:
- case Intrinsic::hexagon_C2_cmpgtp:
- case Intrinsic::hexagon_C2_cmpeqp:
- case Intrinsic::hexagon_C2_bitsset:
- case Intrinsic::hexagon_C2_bitsclr:
- case Intrinsic::hexagon_C2_cmpeqi:
- case Intrinsic::hexagon_C2_cmpgti:
- case Intrinsic::hexagon_C2_cmpgtui:
- case Intrinsic::hexagon_C2_cmpgei:
- case Intrinsic::hexagon_C2_cmpgeui:
- case Intrinsic::hexagon_C2_cmplt:
- case Intrinsic::hexagon_C2_cmpltu:
- case Intrinsic::hexagon_C2_bitsclri:
- case Intrinsic::hexagon_C2_and:
- case Intrinsic::hexagon_C2_or:
- case Intrinsic::hexagon_C2_xor:
- case Intrinsic::hexagon_C2_andn:
- case Intrinsic::hexagon_C2_not:
- case Intrinsic::hexagon_C2_orn:
- case Intrinsic::hexagon_C2_pxfer_map:
- case Intrinsic::hexagon_C2_any8:
- case Intrinsic::hexagon_C2_all8:
- case Intrinsic::hexagon_A2_vcmpbeq:
- case Intrinsic::hexagon_A2_vcmpbgtu:
- case Intrinsic::hexagon_A2_vcmpheq:
- case Intrinsic::hexagon_A2_vcmphgt:
- case Intrinsic::hexagon_A2_vcmphgtu:
- case Intrinsic::hexagon_A2_vcmpweq:
- case Intrinsic::hexagon_A2_vcmpwgt:
- case Intrinsic::hexagon_A2_vcmpwgtu:
- case Intrinsic::hexagon_C2_tfrrp:
- case Intrinsic::hexagon_S2_tstbit_i:
- case Intrinsic::hexagon_S2_tstbit_r:
- return true;
- }
-}
-
void HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl) {
SDValue Chain = LD->getChain();
SDValue Base = LD->getBasePtr();
@@ -138,12 +93,18 @@ void HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl) {
Opcode = IsValidInc ? Hexagon::L2_loadrh_pi : Hexagon::L2_loadrh_io;
break;
case MVT::i32:
+ case MVT::f32:
+ case MVT::v2i16:
+ case MVT::v4i8:
Opcode = IsValidInc ? Hexagon::L2_loadri_pi : Hexagon::L2_loadri_io;
break;
case MVT::i64:
+ case MVT::f64:
+ case MVT::v2i32:
+ case MVT::v4i16:
+ case MVT::v8i8:
Opcode = IsValidInc ? Hexagon::L2_loadrd_pi : Hexagon::L2_loadrd_io;
break;
- // 64B
case MVT::v64i8:
case MVT::v32i16:
case MVT::v16i32:
@@ -223,7 +184,6 @@ void HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl) {
CurDAG->RemoveDeadNode(LD);
}
-
MachineSDNode *HexagonDAGToDAGISel::LoadInstrForLoadIntrinsic(SDNode *IntN) {
if (IntN->getOpcode() != ISD::INTRINSIC_W_CHAIN)
return nullptr;
@@ -241,35 +201,14 @@ MachineSDNode *HexagonDAGToDAGISel::LoadInstrForLoadIntrinsic(SDNode *IntN) {
};
auto FLC = LoadPciMap.find(IntNo);
if (FLC != LoadPciMap.end()) {
- SDNode *Mod = CurDAG->getMachineNode(Hexagon::A2_tfrrcr, dl, MVT::i32,
- IntN->getOperand(4));
EVT ValTy = (IntNo == Intrinsic::hexagon_circ_ldd) ? MVT::i64 : MVT::i32;
EVT RTys[] = { ValTy, MVT::i32, MVT::Other };
// Operands: { Base, Increment, Modifier, Chain }
auto Inc = cast<ConstantSDNode>(IntN->getOperand(5));
SDValue I = CurDAG->getTargetConstant(Inc->getSExtValue(), dl, MVT::i32);
MachineSDNode *Res = CurDAG->getMachineNode(FLC->second, dl, RTys,
- { IntN->getOperand(2), I, SDValue(Mod,0), IntN->getOperand(0) });
- return Res;
- }
-
- static std::map<unsigned,unsigned> LoadPbrMap = {
- { Intrinsic::hexagon_brev_ldb, Hexagon::L2_loadrb_pbr },
- { Intrinsic::hexagon_brev_ldub, Hexagon::L2_loadrub_pbr },
- { Intrinsic::hexagon_brev_ldh, Hexagon::L2_loadrh_pbr },
- { Intrinsic::hexagon_brev_lduh, Hexagon::L2_loadruh_pbr },
- { Intrinsic::hexagon_brev_ldw, Hexagon::L2_loadri_pbr },
- { Intrinsic::hexagon_brev_ldd, Hexagon::L2_loadrd_pbr },
- };
- auto FLB = LoadPbrMap.find(IntNo);
- if (FLB != LoadPbrMap.end()) {
- SDNode *Mod = CurDAG->getMachineNode(Hexagon::A2_tfrrcr, dl, MVT::i32,
- IntN->getOperand(4));
- EVT ValTy = (IntNo == Intrinsic::hexagon_brev_ldd) ? MVT::i64 : MVT::i32;
- EVT RTys[] = { ValTy, MVT::i32, MVT::Other };
- // Operands: { Base, Modifier, Chain }
- MachineSDNode *Res = CurDAG->getMachineNode(FLB->second, dl, RTys,
- { IntN->getOperand(2), SDValue(Mod,0), IntN->getOperand(0) });
+ { IntN->getOperand(2), I, IntN->getOperand(4),
+ IntN->getOperand(0) });
return Res;
}
@@ -343,14 +282,10 @@ bool HexagonDAGToDAGISel::tryLoadOfLoadIntrinsic(LoadSDNode *N) {
// a sign-extending intrinsic into (or the other way around).
ISD::LoadExtType IntExt;
switch (cast<ConstantSDNode>(C->getOperand(1))->getZExtValue()) {
- case Intrinsic::hexagon_brev_ldub:
- case Intrinsic::hexagon_brev_lduh:
case Intrinsic::hexagon_circ_ldub:
case Intrinsic::hexagon_circ_lduh:
IntExt = ISD::ZEXTLOAD;
break;
- case Intrinsic::hexagon_brev_ldw:
- case Intrinsic::hexagon_brev_ldd:
case Intrinsic::hexagon_circ_ldw:
case Intrinsic::hexagon_circ_ldd:
IntExt = ISD::NON_EXTLOAD;
@@ -378,6 +313,134 @@ bool HexagonDAGToDAGISel::tryLoadOfLoadIntrinsic(LoadSDNode *N) {
CurDAG->RemoveDeadNode(C);
return true;
}
+ return false;
+}
+
+// Convert the bit-reverse load intrinsic to appropriate target instruction.
+bool HexagonDAGToDAGISel::SelectBrevLdIntrinsic(SDNode *IntN) {
+ if (IntN->getOpcode() != ISD::INTRINSIC_W_CHAIN)
+ return false;
+
+ const SDLoc &dl(IntN);
+ unsigned IntNo = cast<ConstantSDNode>(IntN->getOperand(1))->getZExtValue();
+
+ static const std::map<unsigned, unsigned> LoadBrevMap = {
+ { Intrinsic::hexagon_L2_loadrb_pbr, Hexagon::L2_loadrb_pbr },
+ { Intrinsic::hexagon_L2_loadrub_pbr, Hexagon::L2_loadrub_pbr },
+ { Intrinsic::hexagon_L2_loadrh_pbr, Hexagon::L2_loadrh_pbr },
+ { Intrinsic::hexagon_L2_loadruh_pbr, Hexagon::L2_loadruh_pbr },
+ { Intrinsic::hexagon_L2_loadri_pbr, Hexagon::L2_loadri_pbr },
+ { Intrinsic::hexagon_L2_loadrd_pbr, Hexagon::L2_loadrd_pbr }
+ };
+ auto FLI = LoadBrevMap.find(IntNo);
+ if (FLI != LoadBrevMap.end()) {
+ EVT ValTy =
+ (IntNo == Intrinsic::hexagon_L2_loadrd_pbr) ? MVT::i64 : MVT::i32;
+ EVT RTys[] = { ValTy, MVT::i32, MVT::Other };
+ // Operands of Intrinsic: {chain, enum ID of intrinsic, baseptr,
+ // modifier}.
+ // Operands of target instruction: { Base, Modifier, Chain }.
+ MachineSDNode *Res = CurDAG->getMachineNode(
+ FLI->second, dl, RTys,
+ {IntN->getOperand(2), IntN->getOperand(3), IntN->getOperand(0)});
+
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = cast<MemIntrinsicSDNode>(IntN)->getMemOperand();
+ Res->setMemRefs(MemOp, MemOp + 1);
+
+ ReplaceUses(SDValue(IntN, 0), SDValue(Res, 0));
+ ReplaceUses(SDValue(IntN, 1), SDValue(Res, 1));
+ ReplaceUses(SDValue(IntN, 2), SDValue(Res, 2));
+ CurDAG->RemoveDeadNode(IntN);
+ return true;
+ }
+ return false;
+}
+
+/// Generate a machine instruction node for the new circlar buffer intrinsics.
+/// The new versions use a CSx register instead of the K field.
+bool HexagonDAGToDAGISel::SelectNewCircIntrinsic(SDNode *IntN) {
+ if (IntN->getOpcode() != ISD::INTRINSIC_W_CHAIN)
+ return false;
+
+ SDLoc DL(IntN);
+ unsigned IntNo = cast<ConstantSDNode>(IntN->getOperand(1))->getZExtValue();
+ SmallVector<SDValue, 7> Ops;
+
+ static std::map<unsigned,unsigned> LoadNPcMap = {
+ { Intrinsic::hexagon_L2_loadrub_pci, Hexagon::PS_loadrub_pci },
+ { Intrinsic::hexagon_L2_loadrb_pci, Hexagon::PS_loadrb_pci },
+ { Intrinsic::hexagon_L2_loadruh_pci, Hexagon::PS_loadruh_pci },
+ { Intrinsic::hexagon_L2_loadrh_pci, Hexagon::PS_loadrh_pci },
+ { Intrinsic::hexagon_L2_loadri_pci, Hexagon::PS_loadri_pci },
+ { Intrinsic::hexagon_L2_loadrd_pci, Hexagon::PS_loadrd_pci },
+ { Intrinsic::hexagon_L2_loadrub_pcr, Hexagon::PS_loadrub_pcr },
+ { Intrinsic::hexagon_L2_loadrb_pcr, Hexagon::PS_loadrb_pcr },
+ { Intrinsic::hexagon_L2_loadruh_pcr, Hexagon::PS_loadruh_pcr },
+ { Intrinsic::hexagon_L2_loadrh_pcr, Hexagon::PS_loadrh_pcr },
+ { Intrinsic::hexagon_L2_loadri_pcr, Hexagon::PS_loadri_pcr },
+ { Intrinsic::hexagon_L2_loadrd_pcr, Hexagon::PS_loadrd_pcr }
+ };
+ auto FLI = LoadNPcMap.find (IntNo);
+ if (FLI != LoadNPcMap.end()) {
+ EVT ValTy = MVT::i32;
+ if (IntNo == Intrinsic::hexagon_L2_loadrd_pci ||
+ IntNo == Intrinsic::hexagon_L2_loadrd_pcr)
+ ValTy = MVT::i64;
+ EVT RTys[] = { ValTy, MVT::i32, MVT::Other };
+ // Handle load.*_pci case which has 6 operands.
+ if (IntN->getNumOperands() == 6) {
+ auto Inc = cast<ConstantSDNode>(IntN->getOperand(3));
+ SDValue I = CurDAG->getTargetConstant(Inc->getSExtValue(), DL, MVT::i32);
+ // Operands: { Base, Increment, Modifier, Start, Chain }.
+ Ops = { IntN->getOperand(2), I, IntN->getOperand(4), IntN->getOperand(5),
+ IntN->getOperand(0) };
+ } else
+ // Handle load.*_pcr case which has 5 operands.
+ // Operands: { Base, Modifier, Start, Chain }.
+ Ops = { IntN->getOperand(2), IntN->getOperand(3), IntN->getOperand(4),
+ IntN->getOperand(0) };
+ MachineSDNode *Res = CurDAG->getMachineNode(FLI->second, DL, RTys, Ops);
+ ReplaceUses(SDValue(IntN, 0), SDValue(Res, 0));
+ ReplaceUses(SDValue(IntN, 1), SDValue(Res, 1));
+ ReplaceUses(SDValue(IntN, 2), SDValue(Res, 2));
+ CurDAG->RemoveDeadNode(IntN);
+ return true;
+ }
+
+ static std::map<unsigned,unsigned> StoreNPcMap = {
+ { Intrinsic::hexagon_S2_storerb_pci, Hexagon::PS_storerb_pci },
+ { Intrinsic::hexagon_S2_storerh_pci, Hexagon::PS_storerh_pci },
+ { Intrinsic::hexagon_S2_storerf_pci, Hexagon::PS_storerf_pci },
+ { Intrinsic::hexagon_S2_storeri_pci, Hexagon::PS_storeri_pci },
+ { Intrinsic::hexagon_S2_storerd_pci, Hexagon::PS_storerd_pci },
+ { Intrinsic::hexagon_S2_storerb_pcr, Hexagon::PS_storerb_pcr },
+ { Intrinsic::hexagon_S2_storerh_pcr, Hexagon::PS_storerh_pcr },
+ { Intrinsic::hexagon_S2_storerf_pcr, Hexagon::PS_storerf_pcr },
+ { Intrinsic::hexagon_S2_storeri_pcr, Hexagon::PS_storeri_pcr },
+ { Intrinsic::hexagon_S2_storerd_pcr, Hexagon::PS_storerd_pcr }
+ };
+ auto FSI = StoreNPcMap.find (IntNo);
+ if (FSI != StoreNPcMap.end()) {
+ EVT RTys[] = { MVT::i32, MVT::Other };
+ // Handle store.*_pci case which has 7 operands.
+ if (IntN->getNumOperands() == 7) {
+ auto Inc = cast<ConstantSDNode>(IntN->getOperand(3));
+ SDValue I = CurDAG->getTargetConstant(Inc->getSExtValue(), DL, MVT::i32);
+ // Operands: { Base, Increment, Modifier, Value, Start, Chain }.
+ Ops = { IntN->getOperand(2), I, IntN->getOperand(4), IntN->getOperand(5),
+ IntN->getOperand(6), IntN->getOperand(0) };
+ } else
+ // Handle store.*_pcr case which has 6 operands.
+ // Operands: { Base, Modifier, Value, Start, Chain }.
+ Ops = { IntN->getOperand(2), IntN->getOperand(3), IntN->getOperand(4),
+ IntN->getOperand(5), IntN->getOperand(0) };
+ MachineSDNode *Res = CurDAG->getMachineNode(FSI->second, DL, RTys, Ops);
+ ReplaceUses(SDValue(IntN, 0), SDValue(Res, 0));
+ ReplaceUses(SDValue(IntN, 1), SDValue(Res, 1));
+ CurDAG->RemoveDeadNode(IntN);
+ return true;
+ }
return false;
}
@@ -385,9 +448,9 @@ bool HexagonDAGToDAGISel::tryLoadOfLoadIntrinsic(LoadSDNode *N) {
void HexagonDAGToDAGISel::SelectLoad(SDNode *N) {
SDLoc dl(N);
LoadSDNode *LD = cast<LoadSDNode>(N);
- ISD::MemIndexedMode AM = LD->getAddressingMode();
// Handle indexed loads.
+ ISD::MemIndexedMode AM = LD->getAddressingMode();
if (AM != ISD::UNINDEXED) {
SelectIndexedLoad(LD, dl);
return;
@@ -422,9 +485,16 @@ void HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl) {
Opcode = IsValidInc ? Hexagon::S2_storerh_pi : Hexagon::S2_storerh_io;
break;
case MVT::i32:
+ case MVT::f32:
+ case MVT::v2i16:
+ case MVT::v4i8:
Opcode = IsValidInc ? Hexagon::S2_storeri_pi : Hexagon::S2_storeri_io;
break;
case MVT::i64:
+ case MVT::f64:
+ case MVT::v2i32:
+ case MVT::v4i16:
+ case MVT::v8i8:
Opcode = IsValidInc ? Hexagon::S2_storerd_pi : Hexagon::S2_storerd_io;
break;
case MVT::v64i8:
@@ -488,9 +558,9 @@ void HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl) {
void HexagonDAGToDAGISel::SelectStore(SDNode *N) {
SDLoc dl(N);
StoreSDNode *ST = cast<StoreSDNode>(N);
- ISD::MemIndexedMode AM = ST->getAddressingMode();
// Handle indexed stores.
+ ISD::MemIndexedMode AM = ST->getAddressingMode();
if (AM != ISD::UNINDEXED) {
SelectIndexedStore(ST, dl);
return;
@@ -553,85 +623,6 @@ void HexagonDAGToDAGISel::SelectSHL(SDNode *N) {
return Default();
}
-
-//
-// If there is an zero_extend followed an intrinsic in DAG (this means - the
-// result of the intrinsic is predicate); convert the zero_extend to
-// transfer instruction.
-//
-// Zero extend -> transfer is lowered here. Otherwise, zero_extend will be
-// converted into a MUX as predicate registers defined as 1 bit in the
-// compiler. Architecture defines them as 8-bit registers.
-// We want to preserve all the lower 8-bits and, not just 1 LSB bit.
-//
-void HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) {
- SDLoc dl(N);
-
- SDValue Op0 = N->getOperand(0);
- EVT OpVT = Op0.getValueType();
- unsigned OpBW = OpVT.getSizeInBits();
-
- // Special handling for zero-extending a vector of booleans.
- if (OpVT.isVector() && OpVT.getVectorElementType() == MVT::i1 && OpBW <= 64) {
- SDNode *Mask = CurDAG->getMachineNode(Hexagon::C2_mask, dl, MVT::i64, Op0);
- unsigned NE = OpVT.getVectorNumElements();
- EVT ExVT = N->getValueType(0);
- unsigned ES = ExVT.getScalarSizeInBits();
- uint64_t MV = 0, Bit = 1;
- for (unsigned i = 0; i < NE; ++i) {
- MV |= Bit;
- Bit <<= ES;
- }
- SDValue Ones = CurDAG->getTargetConstant(MV, dl, MVT::i64);
- SDNode *OnesReg = CurDAG->getMachineNode(Hexagon::CONST64, dl,
- MVT::i64, Ones);
- if (ExVT.getSizeInBits() == 32) {
- SDNode *And = CurDAG->getMachineNode(Hexagon::A2_andp, dl, MVT::i64,
- SDValue(Mask,0), SDValue(OnesReg,0));
- SDValue SubR = CurDAG->getTargetConstant(Hexagon::isub_lo, dl, MVT::i32);
- ReplaceNode(N, CurDAG->getMachineNode(Hexagon::EXTRACT_SUBREG, dl, ExVT,
- SDValue(And, 0), SubR));
- return;
- }
- ReplaceNode(N,
- CurDAG->getMachineNode(Hexagon::A2_andp, dl, ExVT,
- SDValue(Mask, 0), SDValue(OnesReg, 0)));
- return;
- }
-
- SDNode *Int = N->getOperand(0).getNode();
- if ((Int->getOpcode() == ISD::INTRINSIC_WO_CHAIN)) {
- unsigned ID = cast<ConstantSDNode>(Int->getOperand(0))->getZExtValue();
- if (doesIntrinsicReturnPredicate(ID)) {
- // Now we need to differentiate target data types.
- if (N->getValueType(0) == MVT::i64) {
- // Convert the zero_extend to Rs = Pd followed by A2_combinew(0,Rs).
- SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
- SDNode *Result_1 = CurDAG->getMachineNode(Hexagon::C2_tfrpr, dl,
- MVT::i32, SDValue(Int, 0));
- SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl,
- MVT::i32, TargetConst0);
- SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::A2_combinew, dl,
- MVT::i64, MVT::Other,
- SDValue(Result_2, 0),
- SDValue(Result_1, 0));
- ReplaceNode(N, Result_3);
- return;
- }
- if (N->getValueType(0) == MVT::i32) {
- // Convert the zero_extend to Rs = Pd
- SDNode* RsPd = CurDAG->getMachineNode(Hexagon::C2_tfrpr, dl,
- MVT::i32, SDValue(Int, 0));
- ReplaceNode(N, RsPd);
- return;
- }
- llvm_unreachable("Unexpected value type");
- }
- }
- SelectCode(N);
-}
-
-
//
// Handling intrinsics for circular load and bitreverse load.
//
@@ -642,6 +633,13 @@ void HexagonDAGToDAGISel::SelectIntrinsicWChain(SDNode *N) {
return;
}
+ // Handle bit-reverse load intrinsics.
+ if (SelectBrevLdIntrinsic(N))
+ return;
+
+ if (SelectNewCircIntrinsic(N))
+ return;
+
unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
if (IntNo == Intrinsic::hexagon_V6_vgathermw ||
IntNo == Intrinsic::hexagon_V6_vgathermw_128B ||
@@ -735,7 +733,6 @@ void HexagonDAGToDAGISel::SelectConstant(SDNode *N) {
SelectCode(N);
}
-
void HexagonDAGToDAGISel::SelectFrameIndex(SDNode *N) {
MachineFrameInfo &MFI = MF->getFrameInfo();
const HexagonFrameLowering *HFI = HST->getFrameLowering();
@@ -765,20 +762,113 @@ void HexagonDAGToDAGISel::SelectFrameIndex(SDNode *N) {
ReplaceNode(N, R);
}
+void HexagonDAGToDAGISel::SelectAddSubCarry(SDNode *N) {
+ unsigned OpcCarry = N->getOpcode() == HexagonISD::ADDC ? Hexagon::A4_addp_c
+ : Hexagon::A4_subp_c;
+ SDNode *C = CurDAG->getMachineNode(OpcCarry, SDLoc(N), N->getVTList(),
+ { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2) });
+ ReplaceNode(N, C);
+}
-void HexagonDAGToDAGISel::SelectBitcast(SDNode *N) {
- EVT SVT = N->getOperand(0).getValueType();
- EVT DVT = N->getValueType(0);
- if (!SVT.isVector() || !DVT.isVector() ||
- SVT.getVectorElementType() == MVT::i1 ||
- DVT.getVectorElementType() == MVT::i1 ||
- SVT.getSizeInBits() != DVT.getSizeInBits()) {
- SelectCode(N);
- return;
+void HexagonDAGToDAGISel::SelectVAlign(SDNode *N) {
+ MVT ResTy = N->getValueType(0).getSimpleVT();
+ if (HST->isHVXVectorType(ResTy, true))
+ return SelectHvxVAlign(N);
+
+ const SDLoc &dl(N);
+ unsigned VecLen = ResTy.getSizeInBits();
+ if (VecLen == 32) {
+ SDValue Ops[] = {
+ CurDAG->getTargetConstant(Hexagon::DoubleRegsRegClassID, dl, MVT::i32),
+ N->getOperand(0),
+ CurDAG->getTargetConstant(Hexagon::isub_hi, dl, MVT::i32),
+ N->getOperand(1),
+ CurDAG->getTargetConstant(Hexagon::isub_lo, dl, MVT::i32)
+ };
+ SDNode *R = CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl,
+ MVT::i64, Ops);
+
+ // Shift right by "(Addr & 0x3) * 8" bytes.
+ SDValue M0 = CurDAG->getTargetConstant(0x18, dl, MVT::i32);
+ SDValue M1 = CurDAG->getTargetConstant(0x03, dl, MVT::i32);
+ SDNode *C = CurDAG->getMachineNode(Hexagon::S4_andi_asl_ri, dl, MVT::i32,
+ M0, N->getOperand(2), M1);
+ SDNode *S = CurDAG->getMachineNode(Hexagon::S2_lsr_r_p, dl, MVT::i64,
+ SDValue(R, 0), SDValue(C, 0));
+ SDValue E = CurDAG->getTargetExtractSubreg(Hexagon::isub_lo, dl, ResTy,
+ SDValue(S, 0));
+ ReplaceNode(N, E.getNode());
+ } else {
+ assert(VecLen == 64);
+ SDNode *Pu = CurDAG->getMachineNode(Hexagon::C2_tfrrp, dl, MVT::v8i1,
+ N->getOperand(2));
+ SDNode *VA = CurDAG->getMachineNode(Hexagon::S2_valignrb, dl, ResTy,
+ N->getOperand(0), N->getOperand(1),
+ SDValue(Pu,0));
+ ReplaceNode(N, VA);
}
+}
+
+void HexagonDAGToDAGISel::SelectVAlignAddr(SDNode *N) {
+ const SDLoc &dl(N);
+ SDValue A = N->getOperand(1);
+ int Mask = -cast<ConstantSDNode>(A.getNode())->getSExtValue();
+ assert(isPowerOf2_32(-Mask));
+
+ SDValue M = CurDAG->getTargetConstant(Mask, dl, MVT::i32);
+ SDNode *AA = CurDAG->getMachineNode(Hexagon::A2_andir, dl, MVT::i32,
+ N->getOperand(0), M);
+ ReplaceNode(N, AA);
+}
+
+// Handle these nodes here to avoid having to write patterns for all
+// combinations of input/output types. In all cases, the resulting
+// instruction is the same.
+void HexagonDAGToDAGISel::SelectTypecast(SDNode *N) {
+ SDValue Op = N->getOperand(0);
+ MVT OpTy = Op.getValueType().getSimpleVT();
+ SDNode *T = CurDAG->MorphNodeTo(N, N->getOpcode(),
+ CurDAG->getVTList(OpTy), {Op});
+ ReplaceNode(T, Op.getNode());
+}
+
+void HexagonDAGToDAGISel::SelectP2D(SDNode *N) {
+ MVT ResTy = N->getValueType(0).getSimpleVT();
+ SDNode *T = CurDAG->getMachineNode(Hexagon::C2_mask, SDLoc(N), ResTy,
+ N->getOperand(0));
+ ReplaceNode(N, T);
+}
+
+void HexagonDAGToDAGISel::SelectD2P(SDNode *N) {
+ const SDLoc &dl(N);
+ MVT ResTy = N->getValueType(0).getSimpleVT();
+ SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
+ SDNode *T = CurDAG->getMachineNode(Hexagon::A4_vcmpbgtui, dl, ResTy,
+ N->getOperand(0), Zero);
+ ReplaceNode(N, T);
+}
+
+void HexagonDAGToDAGISel::SelectV2Q(SDNode *N) {
+ const SDLoc &dl(N);
+ MVT ResTy = N->getValueType(0).getSimpleVT();
- CurDAG->ReplaceAllUsesOfValueWith(SDValue(N,0), N->getOperand(0));
- CurDAG->RemoveDeadNode(N);
+ SDValue C = CurDAG->getTargetConstant(-1, dl, MVT::i32);
+ SDNode *R = CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl, MVT::i32, C);
+ SDNode *T = CurDAG->getMachineNode(Hexagon::V6_vandvrt, dl, ResTy,
+ N->getOperand(0), SDValue(R,0));
+ ReplaceNode(N, T);
+}
+
+void HexagonDAGToDAGISel::SelectQ2V(SDNode *N) {
+ const SDLoc &dl(N);
+ MVT ResTy = N->getValueType(0).getSimpleVT();
+
+ SDValue C = CurDAG->getTargetConstant(-1, dl, MVT::i32);
+ SDNode *R = CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl, MVT::i32, C);
+ SDNode *T = CurDAG->getMachineNode(Hexagon::V6_vandqrt, dl, ResTy,
+ N->getOperand(0), SDValue(R,0));
+ ReplaceNode(N, T);
}
void HexagonDAGToDAGISel::Select(SDNode *N) {
@@ -789,13 +879,21 @@ void HexagonDAGToDAGISel::Select(SDNode *N) {
case ISD::Constant: return SelectConstant(N);
case ISD::ConstantFP: return SelectConstantFP(N);
case ISD::FrameIndex: return SelectFrameIndex(N);
- case ISD::BITCAST: return SelectBitcast(N);
case ISD::SHL: return SelectSHL(N);
case ISD::LOAD: return SelectLoad(N);
case ISD::STORE: return SelectStore(N);
- case ISD::ZERO_EXTEND: return SelectZeroExtend(N);
case ISD::INTRINSIC_W_CHAIN: return SelectIntrinsicWChain(N);
case ISD::INTRINSIC_WO_CHAIN: return SelectIntrinsicWOChain(N);
+
+ case HexagonISD::ADDC:
+ case HexagonISD::SUBC: return SelectAddSubCarry(N);
+ case HexagonISD::VALIGN: return SelectVAlign(N);
+ case HexagonISD::VALIGNADDR: return SelectVAlignAddr(N);
+ case HexagonISD::TYPECAST: return SelectTypecast(N);
+ case HexagonISD::P2D: return SelectP2D(N);
+ case HexagonISD::D2P: return SelectD2P(N);
+ case HexagonISD::Q2V: return SelectQ2V(N);
+ case HexagonISD::V2Q: return SelectV2Q(N);
}
if (HST->useHVXOps()) {
@@ -1240,7 +1338,7 @@ bool HexagonDAGToDAGISel::SelectAnyImmediate(SDValue &N, SDValue &R,
}
case HexagonISD::JT:
case HexagonISD::CP:
- // These are assumed to always be aligned at at least 8-byte boundary.
+ // These are assumed to always be aligned at least 8-byte boundary.
if (LogAlign > 3)
return false;
R = N.getOperand(0);
@@ -1252,7 +1350,7 @@ bool HexagonDAGToDAGISel::SelectAnyImmediate(SDValue &N, SDValue &R,
R = N;
return true;
case ISD::BlockAddress:
- // Block address is always aligned at at least 4-byte boundary.
+ // Block address is always aligned at least 4-byte boundary.
if (LogAlign > 2 || !IsAligned(cast<BlockAddressSDNode>(N)->getOffset()))
return false;
R = N;
@@ -1345,9 +1443,13 @@ bool HexagonDAGToDAGISel::DetectUseSxtw(SDValue &N, SDValue &R) {
EVT T = Opc == ISD::SIGN_EXTEND
? N.getOperand(0).getValueType()
: cast<VTSDNode>(N.getOperand(1))->getVT();
- if (T.getSizeInBits() != 32)
+ unsigned SW = T.getSizeInBits();
+ if (SW == 32)
+ R = N.getOperand(0);
+ else if (SW < 32)
+ R = N;
+ else
return false;
- R = N.getOperand(0);
break;
}
case ISD::LOAD: {
@@ -1361,6 +1463,13 @@ bool HexagonDAGToDAGISel::DetectUseSxtw(SDValue &N, SDValue &R) {
R = N;
break;
}
+ case ISD::SRA: {
+ auto *S = dyn_cast<ConstantSDNode>(N.getOperand(1));
+ if (!S || S->getZExtValue() != 32)
+ return false;
+ R = N;
+ break;
+ }
default:
return false;
}
@@ -1500,7 +1609,7 @@ static bool isOpcodeHandled(const SDNode *N) {
}
}
-/// \brief Return the weight of an SDNode
+/// Return the weight of an SDNode
int HexagonDAGToDAGISel::getWeight(SDNode *N) {
if (!isOpcodeHandled(N))
return 1;
@@ -1799,15 +1908,15 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
RootHeights[N] = std::max(getHeight(N->getOperand(0).getNode()),
getHeight(N->getOperand(1).getNode())) + 1;
- DEBUG(dbgs() << "--> No need to balance root (Weight=" << Weight
- << " Height=" << RootHeights[N] << "): ");
- DEBUG(N->dump());
+ LLVM_DEBUG(dbgs() << "--> No need to balance root (Weight=" << Weight
+ << " Height=" << RootHeights[N] << "): ");
+ LLVM_DEBUG(N->dump(CurDAG));
return SDValue(N, 0);
}
- DEBUG(dbgs() << "** Balancing root node: ");
- DEBUG(N->dump());
+ LLVM_DEBUG(dbgs() << "** Balancing root node: ");
+ LLVM_DEBUG(N->dump(CurDAG));
unsigned NOpcode = N->getOpcode();
@@ -1855,7 +1964,7 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
// Whoops, this node was RAUWd by one of the balanceSubTree calls we
// made. Our worklist isn't up to date anymore.
// Restart the whole process.
- DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
+ LLVM_DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
return balanceSubTree(N, TopLevel);
}
@@ -1926,15 +2035,15 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
}
}
- DEBUG(dbgs() << "--> Current height=" << NodeHeights[SDValue(N, 0)]
- << " weight=" << CurrentWeight << " imbalanced="
- << Imbalanced << "\n");
+ LLVM_DEBUG(dbgs() << "--> Current height=" << NodeHeights[SDValue(N, 0)]
+ << " weight=" << CurrentWeight
+ << " imbalanced=" << Imbalanced << "\n");
// Transform MUL(x, C * 2^Y) + SHL(z, Y) -> SHL(ADD(MUL(x, C), z), Y)
// This factors out a shift in order to match memw(a<<Y+b).
if (CanFactorize && (willShiftRightEliminate(Mul1.Value, MaxPowerOf2) ||
willShiftRightEliminate(Mul2.Value, MaxPowerOf2))) {
- DEBUG(dbgs() << "--> Found common factor for two MUL children!\n");
+ LLVM_DEBUG(dbgs() << "--> Found common factor for two MUL children!\n");
int Weight = Mul1.Weight + Mul2.Weight;
int Height = std::max(NodeHeights[Mul1.Value], NodeHeights[Mul2.Value]) + 1;
SDValue Mul1Factored = factorOutPowerOf2(Mul1.Value, MaxPowerOf2);
@@ -1968,9 +2077,9 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
if (getUsesInFunction(GANode->getGlobal()) == 1 && Offset->hasOneUse() &&
getTargetLowering()->isOffsetFoldingLegal(GANode)) {
- DEBUG(dbgs() << "--> Combining GA and offset (" << Offset->getSExtValue()
- << "): ");
- DEBUG(GANode->dump());
+ LLVM_DEBUG(dbgs() << "--> Combining GA and offset ("
+ << Offset->getSExtValue() << "): ");
+ LLVM_DEBUG(GANode->dump(CurDAG));
SDValue NewTGA =
CurDAG->getTargetGlobalAddress(GANode->getGlobal(), SDLoc(GA.Value),
@@ -2014,7 +2123,7 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
// If this is the top level and we haven't factored out a shift, we should try
// to move a constant to the bottom to match addressing modes like memw(rX+C)
if (TopLevel && !CanFactorize && Leaves.hasConst()) {
- DEBUG(dbgs() << "--> Pushing constant to tip of tree.");
+ LLVM_DEBUG(dbgs() << "--> Pushing constant to tip of tree.");
Leaves.pushToBottom(Leaves.pop());
}
@@ -2041,7 +2150,7 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
// Make sure that none of these nodes have been RAUW'd
if ((RootWeights.count(V0.getNode()) && RootWeights[V0.getNode()] == -2) ||
(RootWeights.count(V1.getNode()) && RootWeights[V1.getNode()] == -2)) {
- DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
+ LLVM_DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
return balanceSubTree(N, TopLevel);
}
@@ -2075,9 +2184,9 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
int Weight = V0Weight + V1Weight;
Leaves.push(WeightedLeaf(NewNode, Weight, L0.InsertionOrder));
- DEBUG(dbgs() << "--> Built new node (Weight=" << Weight << ",Height="
- << Height << "):\n");
- DEBUG(NewNode.dump());
+ LLVM_DEBUG(dbgs() << "--> Built new node (Weight=" << Weight
+ << ",Height=" << Height << "):\n");
+ LLVM_DEBUG(NewNode.dump());
}
assert(Leaves.size() == 1);
@@ -2101,15 +2210,15 @@ SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
}
if (N != NewRoot.getNode()) {
- DEBUG(dbgs() << "--> Root is now: ");
- DEBUG(NewRoot.dump());
+ LLVM_DEBUG(dbgs() << "--> Root is now: ");
+ LLVM_DEBUG(NewRoot.dump());
// Replace all uses of old root by new root
CurDAG->ReplaceAllUsesWith(N, NewRoot.getNode());
// Mark that we have RAUW'd N
RootWeights[N] = -2;
} else {
- DEBUG(dbgs() << "--> Root unchanged.\n");
+ LLVM_DEBUG(dbgs() << "--> Root unchanged.\n");
}
RootWeights[NewRoot.getNode()] = Leaves.top().Weight;
@@ -2132,8 +2241,8 @@ void HexagonDAGToDAGISel::rebalanceAddressTrees() {
if (RootWeights.count(BasePtr.getNode()))
continue;
- DEBUG(dbgs() << "** Rebalancing address calculation in node: ");
- DEBUG(N->dump());
+ LLVM_DEBUG(dbgs() << "** Rebalancing address calculation in node: ");
+ LLVM_DEBUG(N->dump(CurDAG));
// FindRoots
SmallVector<SDNode *, 4> Worklist;
@@ -2173,8 +2282,8 @@ void HexagonDAGToDAGISel::rebalanceAddressTrees() {
N = CurDAG->UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1),
NewBasePtr, N->getOperand(3));
- DEBUG(dbgs() << "--> Final node: ");
- DEBUG(N->dump());
+ LLVM_DEBUG(dbgs() << "--> Final node: ");
+ LLVM_DEBUG(N->dump(CurDAG));
}
CurDAG->RemoveDeadNodes();
@@ -2182,4 +2291,3 @@ void HexagonDAGToDAGISel::rebalanceAddressTrees() {
RootHeights.clear();
RootWeights.clear();
}
-