aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/Hexagon
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Hexagon')
-rw-r--r--lib/Target/Hexagon/HexagonISelDAGToDAG.cpp189
-rw-r--r--lib/Target/Hexagon/HexagonISelLowering.cpp6
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfo.cpp170
-rw-r--r--lib/Target/Hexagon/HexagonInstrInfo.h5
-rw-r--r--lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp8
-rw-r--r--lib/Target/Hexagon/HexagonPatterns.td59
-rw-r--r--lib/Target/Hexagon/HexagonTargetMachine.cpp4
-rw-r--r--lib/Target/Hexagon/HexagonVLIWPacketizer.cpp49
8 files changed, 157 insertions, 333 deletions
diff --git a/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
index 8e10c521a77d..e4434136bf86 100644
--- a/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
+++ b/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
@@ -71,6 +71,9 @@ public:
return true;
}
+ bool ComplexPatternFuncMutatesDAG() const override {
+ return true;
+ }
void PreprocessISelDAG() override;
void EmitFunctionEntryCode() override;
@@ -81,6 +84,7 @@ public:
inline bool SelectAddrGP(SDValue &N, SDValue &R);
bool SelectGlobalAddress(SDValue &N, SDValue &R, bool UseGP);
bool SelectAddrFI(SDValue &N, SDValue &R);
+ bool DetectUseSxtw(SDValue &N, SDValue &R);
StringRef getPassName() const override {
return "Hexagon DAG->DAG Pattern Instruction Selection";
@@ -106,7 +110,6 @@ public:
void SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl);
void SelectStore(SDNode *N);
void SelectSHL(SDNode *N);
- void SelectMul(SDNode *N);
void SelectZeroExtend(SDNode *N);
void SelectIntrinsicWChain(SDNode *N);
void SelectIntrinsicWOChain(SDNode *N);
@@ -118,7 +121,7 @@ public:
#include "HexagonGenDAGISel.inc"
private:
- bool isValueExtension(const SDValue &Val, unsigned FromBits, SDValue &Src);
+ bool keepsLowBits(const SDValue &Val, unsigned NumBits, SDValue &Src);
bool isOrEquivalentToAdd(const SDNode *N) const;
bool isAlignedMemNode(const MemSDNode *N) const;
bool isPositiveHalfWord(const SDNode *N) const;
@@ -597,90 +600,6 @@ void HexagonDAGToDAGISel::SelectStore(SDNode *N) {
SelectCode(ST);
}
-void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
- SDLoc dl(N);
-
- // %conv.i = sext i32 %tmp1 to i64
- // %conv2.i = sext i32 %add to i64
- // %mul.i = mul nsw i64 %conv2.i, %conv.i
- //
- // --- match with the following ---
- //
- // %mul.i = mpy (%tmp1, %add)
- //
-
- if (N->getValueType(0) == MVT::i64) {
- // Shifting a i64 signed multiply.
- SDValue MulOp0 = N->getOperand(0);
- SDValue MulOp1 = N->getOperand(1);
-
- SDValue OP0;
- SDValue OP1;
-
- // Handle sign_extend and sextload.
- if (MulOp0.getOpcode() == ISD::SIGN_EXTEND) {
- SDValue Sext0 = MulOp0.getOperand(0);
- if (Sext0.getNode()->getValueType(0) != MVT::i32) {
- SelectCode(N);
- return;
- }
- OP0 = Sext0;
- } else if (MulOp0.getOpcode() == ISD::LOAD) {
- LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode());
- if (LD->getMemoryVT() != MVT::i32 ||
- LD->getExtensionType() != ISD::SEXTLOAD ||
- LD->getAddressingMode() != ISD::UNINDEXED) {
- SelectCode(N);
- return;
- }
- SDValue Chain = LD->getChain();
- SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
- OP0 = SDValue(CurDAG->getMachineNode(Hexagon::L2_loadri_io, dl, MVT::i32,
- MVT::Other,
- LD->getBasePtr(), TargetConst0,
- Chain), 0);
- } else {
- SelectCode(N);
- return;
- }
-
- // Same goes for the second operand.
- if (MulOp1.getOpcode() == ISD::SIGN_EXTEND) {
- SDValue Sext1 = MulOp1.getOperand(0);
- if (Sext1.getNode()->getValueType(0) != MVT::i32) {
- SelectCode(N);
- return;
- }
- OP1 = Sext1;
- } else if (MulOp1.getOpcode() == ISD::LOAD) {
- LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode());
- if (LD->getMemoryVT() != MVT::i32 ||
- LD->getExtensionType() != ISD::SEXTLOAD ||
- LD->getAddressingMode() != ISD::UNINDEXED) {
- SelectCode(N);
- return;
- }
- SDValue Chain = LD->getChain();
- SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
- OP1 = SDValue(CurDAG->getMachineNode(Hexagon::L2_loadri_io, dl, MVT::i32,
- MVT::Other,
- LD->getBasePtr(), TargetConst0,
- Chain), 0);
- } else {
- SelectCode(N);
- return;
- }
-
- // Generate a mpy instruction.
- SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_dpmpyss_s0, dl,
- MVT::i64, OP0, OP1);
- ReplaceNode(N, Result);
- return;
- }
-
- SelectCode(N);
-}
-
void HexagonDAGToDAGISel::SelectSHL(SDNode *N) {
SDLoc dl(N);
SDValue Shl_0 = N->getOperand(0);
@@ -843,7 +762,7 @@ void HexagonDAGToDAGISel::SelectIntrinsicWOChain(SDNode *N) {
SDValue V = N->getOperand(1);
SDValue U;
- if (isValueExtension(V, Bits, U)) {
+ if (keepsLowBits(V, Bits, U)) {
SDValue R = CurDAG->getNode(N->getOpcode(), SDLoc(N), N->getValueType(0),
N->getOperand(0), U);
ReplaceNode(N, R.getNode());
@@ -949,7 +868,6 @@ void HexagonDAGToDAGISel::Select(SDNode *N) {
case ISD::SHL: return SelectSHL(N);
case ISD::LOAD: return SelectLoad(N);
case ISD::STORE: return SelectStore(N);
- case ISD::MUL: return SelectMul(N);
case ISD::ZERO_EXTEND: return SelectZeroExtend(N);
case ISD::INTRINSIC_W_CHAIN: return SelectIntrinsicWChain(N);
case ISD::INTRINSIC_WO_CHAIN: return SelectIntrinsicWOChain(N);
@@ -1327,7 +1245,7 @@ void HexagonDAGToDAGISel::EmitFunctionEntryCode() {
}
// Match a frame index that can be used in an addressing mode.
-bool HexagonDAGToDAGISel::SelectAddrFI(SDValue& N, SDValue &R) {
+bool HexagonDAGToDAGISel::SelectAddrFI(SDValue &N, SDValue &R) {
if (N.getOpcode() != ISD::FrameIndex)
return false;
auto &HFI = *HST->getFrameLowering();
@@ -1388,16 +1306,83 @@ bool HexagonDAGToDAGISel::SelectGlobalAddress(SDValue &N, SDValue &R,
return false;
}
-bool HexagonDAGToDAGISel::isValueExtension(const SDValue &Val,
- unsigned FromBits, SDValue &Src) {
+bool HexagonDAGToDAGISel::DetectUseSxtw(SDValue &N, SDValue &R) {
+ // This (complex pattern) function is meant to detect a sign-extension
+ // i32->i64 on a per-operand basis. This would allow writing single
+ // patterns that would cover a number of combinations of different ways
+ // a sign-extensions could be written. For example:
+ // (mul (DetectUseSxtw x) (DetectUseSxtw y)) -> (M2_dpmpyss_s0 x y)
+ // could match either one of these:
+ // (mul (sext x) (sext_inreg y))
+ // (mul (sext-load *p) (sext_inreg y))
+ // (mul (sext_inreg x) (sext y))
+ // etc.
+ //
+ // The returned value will have type i64 and its low word will
+ // contain the value being extended. The high bits are not specified.
+ // The returned type is i64 because the original type of N was i64,
+ // but the users of this function should only use the low-word of the
+ // result, e.g.
+ // (mul sxtw:x, sxtw:y) -> (M2_dpmpyss_s0 (LoReg sxtw:x), (LoReg sxtw:y))
+
+ if (N.getValueType() != MVT::i64)
+ return false;
+ EVT SrcVT;
+ unsigned Opc = N.getOpcode();
+ switch (Opc) {
+ case ISD::SIGN_EXTEND:
+ case ISD::SIGN_EXTEND_INREG: {
+ // sext_inreg has the source type as a separate operand.
+ EVT T = Opc == ISD::SIGN_EXTEND
+ ? N.getOperand(0).getValueType()
+ : cast<VTSDNode>(N.getOperand(1))->getVT();
+ if (T.getSizeInBits() != 32)
+ return false;
+ R = N.getOperand(0);
+ break;
+ }
+ case ISD::LOAD: {
+ LoadSDNode *L = cast<LoadSDNode>(N);
+ if (L->getExtensionType() != ISD::SEXTLOAD)
+ return false;
+ // All extending loads extend to i32, so even if the value in
+ // memory is shorter than 32 bits, it will be i32 after the load.
+ if (L->getMemoryVT().getSizeInBits() > 32)
+ return false;
+ R = N;
+ break;
+ }
+ default:
+ return false;
+ }
+ EVT RT = R.getValueType();
+ if (RT == MVT::i64)
+ return true;
+ assert(RT == MVT::i32);
+ // This is only to produce a value of type i64. Do not rely on the
+ // high bits produced by this.
+ const SDLoc &dl(N);
+ SDValue Ops[] = {
+ CurDAG->getTargetConstant(Hexagon::DoubleRegsRegClassID, dl, MVT::i32),
+ R, CurDAG->getTargetConstant(Hexagon::isub_hi, dl, MVT::i32),
+ R, CurDAG->getTargetConstant(Hexagon::isub_lo, dl, MVT::i32)
+ };
+ SDNode *T = CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl,
+ MVT::i64, Ops);
+ R = SDValue(T, 0);
+ return true;
+}
+
+bool HexagonDAGToDAGISel::keepsLowBits(const SDValue &Val, unsigned NumBits,
+ SDValue &Src) {
unsigned Opc = Val.getOpcode();
switch (Opc) {
case ISD::SIGN_EXTEND:
case ISD::ZERO_EXTEND:
case ISD::ANY_EXTEND: {
- SDValue const &Op0 = Val.getOperand(0);
+ const SDValue &Op0 = Val.getOperand(0);
EVT T = Op0.getValueType();
- if (T.isInteger() && T.getSizeInBits() == FromBits) {
+ if (T.isInteger() && T.getSizeInBits() == NumBits) {
Src = Op0;
return true;
}
@@ -1408,23 +1393,23 @@ bool HexagonDAGToDAGISel::isValueExtension(const SDValue &Val,
case ISD::AssertZext:
if (Val.getOperand(0).getValueType().isInteger()) {
VTSDNode *T = cast<VTSDNode>(Val.getOperand(1));
- if (T->getVT().getSizeInBits() == FromBits) {
+ if (T->getVT().getSizeInBits() == NumBits) {
Src = Val.getOperand(0);
return true;
}
}
break;
case ISD::AND: {
- // Check if this is an AND with "FromBits" of lower bits set to 1.
- uint64_t FromMask = (1 << FromBits) - 1;
+ // Check if this is an AND with NumBits of lower bits set to 1.
+ uint64_t Mask = (1 << NumBits) - 1;
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(0))) {
- if (C->getZExtValue() == FromMask) {
+ if (C->getZExtValue() == Mask) {
Src = Val.getOperand(1);
return true;
}
}
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(1))) {
- if (C->getZExtValue() == FromMask) {
+ if (C->getZExtValue() == Mask) {
Src = Val.getOperand(0);
return true;
}
@@ -1433,16 +1418,16 @@ bool HexagonDAGToDAGISel::isValueExtension(const SDValue &Val,
}
case ISD::OR:
case ISD::XOR: {
- // OR/XOR with the lower "FromBits" bits set to 0.
- uint64_t FromMask = (1 << FromBits) - 1;
+ // OR/XOR with the lower NumBits bits set to 0.
+ uint64_t Mask = (1 << NumBits) - 1;
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(0))) {
- if ((C->getZExtValue() & FromMask) == 0) {
+ if ((C->getZExtValue() & Mask) == 0) {
Src = Val.getOperand(1);
return true;
}
}
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(1))) {
- if ((C->getZExtValue() & FromMask) == 0) {
+ if ((C->getZExtValue() & Mask) == 0) {
Src = Val.getOperand(0);
return true;
}
diff --git a/lib/Target/Hexagon/HexagonISelLowering.cpp b/lib/Target/Hexagon/HexagonISelLowering.cpp
index 5ecf9320d5c2..4c6c6eeafbe0 100644
--- a/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -1928,11 +1928,7 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
setOperationAction(ISD::BSWAP, MVT::i32, Legal);
setOperationAction(ISD::BSWAP, MVT::i64, Legal);
-
- // We custom lower i64 to i64 mul, so that it is not considered as a legal
- // operation. There is a pattern that will match i64 mul and transform it
- // to a series of instructions.
- setOperationAction(ISD::MUL, MVT::i64, Expand);
+ setOperationAction(ISD::MUL, MVT::i64, Legal);
for (unsigned IntExpOp :
{ ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM,
diff --git a/lib/Target/Hexagon/HexagonInstrInfo.cpp b/lib/Target/Hexagon/HexagonInstrInfo.cpp
index 66e07c67958e..0fef91ec4d3e 100644
--- a/lib/Target/Hexagon/HexagonInstrInfo.cpp
+++ b/lib/Target/Hexagon/HexagonInstrInfo.cpp
@@ -1769,161 +1769,6 @@ bool HexagonInstrInfo::isCompoundBranchInstr(const MachineInstr &MI) const {
return getType(MI) == HexagonII::TypeCJ && MI.isBranch();
}
-bool HexagonInstrInfo::isCondInst(const MachineInstr &MI) const {
- return (MI.isBranch() && isPredicated(MI)) ||
- isConditionalTransfer(MI) ||
- isConditionalALU32(MI) ||
- isConditionalLoad(MI) ||
- // Predicated stores which don't have a .new on any operands.
- (MI.mayStore() && isPredicated(MI) && !isNewValueStore(MI) &&
- !isPredicatedNew(MI));
-}
-
-bool HexagonInstrInfo::isConditionalALU32(const MachineInstr &MI) const {
- switch (MI.getOpcode()) {
- case Hexagon::A2_paddf:
- case Hexagon::A2_paddfnew:
- case Hexagon::A2_paddif:
- case Hexagon::A2_paddifnew:
- case Hexagon::A2_paddit:
- case Hexagon::A2_padditnew:
- case Hexagon::A2_paddt:
- case Hexagon::A2_paddtnew:
- case Hexagon::A2_pandf:
- case Hexagon::A2_pandfnew:
- case Hexagon::A2_pandt:
- case Hexagon::A2_pandtnew:
- case Hexagon::A2_porf:
- case Hexagon::A2_porfnew:
- case Hexagon::A2_port:
- case Hexagon::A2_portnew:
- case Hexagon::A2_psubf:
- case Hexagon::A2_psubfnew:
- case Hexagon::A2_psubt:
- case Hexagon::A2_psubtnew:
- case Hexagon::A2_pxorf:
- case Hexagon::A2_pxorfnew:
- case Hexagon::A2_pxort:
- case Hexagon::A2_pxortnew:
- case Hexagon::A4_paslhf:
- case Hexagon::A4_paslhfnew:
- case Hexagon::A4_paslht:
- case Hexagon::A4_paslhtnew:
- case Hexagon::A4_pasrhf:
- case Hexagon::A4_pasrhfnew:
- case Hexagon::A4_pasrht:
- case Hexagon::A4_pasrhtnew:
- case Hexagon::A4_psxtbf:
- case Hexagon::A4_psxtbfnew:
- case Hexagon::A4_psxtbt:
- case Hexagon::A4_psxtbtnew:
- case Hexagon::A4_psxthf:
- case Hexagon::A4_psxthfnew:
- case Hexagon::A4_psxtht:
- case Hexagon::A4_psxthtnew:
- case Hexagon::A4_pzxtbf:
- case Hexagon::A4_pzxtbfnew:
- case Hexagon::A4_pzxtbt:
- case Hexagon::A4_pzxtbtnew:
- case Hexagon::A4_pzxthf:
- case Hexagon::A4_pzxthfnew:
- case Hexagon::A4_pzxtht:
- case Hexagon::A4_pzxthtnew:
- case Hexagon::C2_ccombinewf:
- case Hexagon::C2_ccombinewt:
- return true;
- }
- return false;
-}
-
-// FIXME - Function name and it's functionality don't match.
-// It should be renamed to hasPredNewOpcode()
-bool HexagonInstrInfo::isConditionalLoad(const MachineInstr &MI) const {
- if (!MI.getDesc().mayLoad() || !isPredicated(MI))
- return false;
-
- int PNewOpcode = Hexagon::getPredNewOpcode(MI.getOpcode());
- // Instruction with valid predicated-new opcode can be promoted to .new.
- return PNewOpcode >= 0;
-}
-
-// Returns true if an instruction is a conditional store.
-//
-// Note: It doesn't include conditional new-value stores as they can't be
-// converted to .new predicate.
-bool HexagonInstrInfo::isConditionalStore(const MachineInstr &MI) const {
- switch (MI.getOpcode()) {
- default: return false;
- case Hexagon::S4_storeirbt_io:
- case Hexagon::S4_storeirbf_io:
- case Hexagon::S4_pstorerbt_rr:
- case Hexagon::S4_pstorerbf_rr:
- case Hexagon::S2_pstorerbt_io:
- case Hexagon::S2_pstorerbf_io:
- case Hexagon::S2_pstorerbt_pi:
- case Hexagon::S2_pstorerbf_pi:
- case Hexagon::S2_pstorerdt_io:
- case Hexagon::S2_pstorerdf_io:
- case Hexagon::S4_pstorerdt_rr:
- case Hexagon::S4_pstorerdf_rr:
- case Hexagon::S2_pstorerdt_pi:
- case Hexagon::S2_pstorerdf_pi:
- case Hexagon::S2_pstorerht_io:
- case Hexagon::S2_pstorerhf_io:
- case Hexagon::S4_storeirht_io:
- case Hexagon::S4_storeirhf_io:
- case Hexagon::S4_pstorerht_rr:
- case Hexagon::S4_pstorerhf_rr:
- case Hexagon::S2_pstorerht_pi:
- case Hexagon::S2_pstorerhf_pi:
- case Hexagon::S2_pstorerit_io:
- case Hexagon::S2_pstorerif_io:
- case Hexagon::S4_storeirit_io:
- case Hexagon::S4_storeirif_io:
- case Hexagon::S4_pstorerit_rr:
- case Hexagon::S4_pstorerif_rr:
- case Hexagon::S2_pstorerit_pi:
- case Hexagon::S2_pstorerif_pi:
-
- // V4 global address store before promoting to dot new.
- case Hexagon::S4_pstorerdt_abs:
- case Hexagon::S4_pstorerdf_abs:
- case Hexagon::S4_pstorerbt_abs:
- case Hexagon::S4_pstorerbf_abs:
- case Hexagon::S4_pstorerht_abs:
- case Hexagon::S4_pstorerhf_abs:
- case Hexagon::S4_pstorerit_abs:
- case Hexagon::S4_pstorerif_abs:
- return true;
-
- // Predicated new value stores (i.e. if (p0) memw(..)=r0.new) are excluded
- // from the "Conditional Store" list. Because a predicated new value store
- // would NOT be promoted to a double dot new store.
- // This function returns yes for those stores that are predicated but not
- // yet promoted to predicate dot new instructions.
- }
-}
-
-bool HexagonInstrInfo::isConditionalTransfer(const MachineInstr &MI) const {
- switch (MI.getOpcode()) {
- case Hexagon::A2_tfrt:
- case Hexagon::A2_tfrf:
- case Hexagon::C2_cmoveit:
- case Hexagon::C2_cmoveif:
- case Hexagon::A2_tfrtnew:
- case Hexagon::A2_tfrfnew:
- case Hexagon::C2_cmovenewit:
- case Hexagon::C2_cmovenewif:
- case Hexagon::A2_tfrpt:
- case Hexagon::A2_tfrpf:
- return true;
-
- default:
- return false;
- }
- return false;
-}
-
// TODO: In order to have isExtendable for fpimm/f32Ext, we need to handle
// isFPImm and later getFPImm as well.
bool HexagonInstrInfo::isConstExtended(const MachineInstr &MI) const {
@@ -3474,6 +3319,8 @@ int HexagonInstrInfo::getDotNewOp(const MachineInstr &MI) const {
// Returns the opcode to use when converting MI, which is a conditional jump,
// into a conditional instruction which uses the .new value of the predicate.
// We also use branch probabilities to add a hint to the jump.
+// If MBPI is null, all edges will be treated as equally likely for the
+// purposes of establishing a predication hint.
int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr &MI,
const MachineBranchProbabilityInfo *MBPI) const {
// We assume that block can have at most two successors.
@@ -3482,9 +3329,16 @@ int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr &MI,
bool Taken = false;
const BranchProbability OneHalf(1, 2);
+ auto getEdgeProbability = [MBPI] (const MachineBasicBlock *Src,
+ const MachineBasicBlock *Dst) {
+ if (MBPI)
+ return MBPI->getEdgeProbability(Src, Dst);
+ return BranchProbability(1, Src->succ_size());
+ };
+
if (BrTarget.isMBB()) {
const MachineBasicBlock *Dst = BrTarget.getMBB();
- Taken = MBPI->getEdgeProbability(Src, Dst) >= OneHalf;
+ Taken = getEdgeProbability(Src, Dst) >= OneHalf;
} else {
// The branch target is not a basic block (most likely a function).
// Since BPI only gives probabilities for targets that are basic blocks,
@@ -3521,7 +3375,7 @@ int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr &MI,
for (const MachineBasicBlock *SB : B.successors()) {
if (!B.isLayoutSuccessor(SB))
continue;
- Taken = MBPI->getEdgeProbability(Src, SB) < OneHalf;
+ Taken = getEdgeProbability(Src, SB) < OneHalf;
break;
}
} else {
@@ -3534,7 +3388,7 @@ int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr &MI,
BT = Op.getMBB();
break;
}
- Taken = BT && MBPI->getEdgeProbability(Src, BT) < OneHalf;
+ Taken = BT && getEdgeProbability(Src, BT) < OneHalf;
}
} // if (!Bad)
}
diff --git a/lib/Target/Hexagon/HexagonInstrInfo.h b/lib/Target/Hexagon/HexagonInstrInfo.h
index 97b9bc954688..944d0161a7c8 100644
--- a/lib/Target/Hexagon/HexagonInstrInfo.h
+++ b/lib/Target/Hexagon/HexagonInstrInfo.h
@@ -314,11 +314,6 @@ public:
bool isAccumulator(const MachineInstr &MI) const;
bool isComplex(const MachineInstr &MI) const;
bool isCompoundBranchInstr(const MachineInstr &MI) const;
- bool isCondInst(const MachineInstr &MI) const;
- bool isConditionalALU32 (const MachineInstr &MI) const;
- bool isConditionalLoad(const MachineInstr &MI) const;
- bool isConditionalStore(const MachineInstr &MI) const;
- bool isConditionalTransfer(const MachineInstr &MI) const;
bool isConstExtended(const MachineInstr &MI) const;
bool isDeallocRet(const MachineInstr &MI) const;
bool isDependent(const MachineInstr &ProdMI,
diff --git a/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp b/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp
index e6ea67d55b43..9aa185fc85a6 100644
--- a/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp
+++ b/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp
@@ -59,6 +59,9 @@ cl::opt<bool> HexagonVolatileMemcpy("disable-hexagon-volatile-memcpy",
cl::Hidden, cl::init(false),
cl::desc("Enable Hexagon-specific memcpy for volatile destination."));
+static cl::opt<unsigned> SimplifyLimit("hlir-simplify-limit", cl::init(10000),
+ cl::Hidden, cl::desc("Maximum number of simplification steps in HLIR"));
+
static const char *HexagonVolatileMemcpyName
= "hexagon_memcpy_forward_vp4cp4n2";
@@ -477,7 +480,7 @@ Value *Simplifier::simplify(Context &C) {
WorkListType Q;
Q.push_back(C.Root);
unsigned Count = 0;
- const unsigned Limit = 100000;
+ const unsigned Limit = SimplifyLimit;
while (!Q.empty()) {
if (Count++ >= Limit)
@@ -501,8 +504,7 @@ Value *Simplifier::simplify(Context &C) {
Q.push_back(Op);
}
}
- assert(Count < Limit && "Infinite loop in HLIR/simplify?");
- return C.Root;
+ return Count < Limit ? C.Root : nullptr;
}
diff --git a/lib/Target/Hexagon/HexagonPatterns.td b/lib/Target/Hexagon/HexagonPatterns.td
index 81b5e10c1173..70ed123bc898 100644
--- a/lib/Target/Hexagon/HexagonPatterns.td
+++ b/lib/Target/Hexagon/HexagonPatterns.td
@@ -382,48 +382,42 @@ def: T_MType_acc_pat3 <M4_or_andn, and, or>;
def: T_MType_acc_pat3 <M4_and_andn, and, and>;
def: T_MType_acc_pat3 <M4_xor_andn, and, xor>;
+// This complex pattern is really only to detect various forms of
+// sign-extension i32->i64. The selected value will be of type i64
+// whose low word is the value being extended. The high word is
+// unspecified.
+def Usxtw : ComplexPattern<i64, 1, "DetectUseSxtw", [], []>;
+
def Aext64: PatFrag<(ops node:$Rs), (i64 (anyext node:$Rs))>;
-def Sext64: PatFrag<(ops node:$Rs), (i64 (sext node:$Rs))>;
def Zext64: PatFrag<(ops node:$Rs), (i64 (zext node:$Rs))>;
+def Sext64: PatLeaf<(i64 Usxtw:$Rs)>;
-// Return true if for a 32 to 64-bit sign-extended load.
-def Sext64Ld : PatLeaf<(i64 DoubleRegs:$src1), [{
- LoadSDNode *LD = dyn_cast<LoadSDNode>(N);
- if (!LD)
- return false;
- return LD->getExtensionType() == ISD::SEXTLOAD &&
- LD->getMemoryVT().getScalarType() == MVT::i32;
-}]>;
-
-def: Pat<(mul (Aext64 I32:$src1), (Aext64 I32:$src2)),
- (M2_dpmpyuu_s0 IntRegs:$src1, IntRegs:$src2)>;
-
-def: Pat<(mul (Sext64 I32:$src1), (Sext64 I32:$src2)),
- (M2_dpmpyss_s0 IntRegs:$src1, IntRegs:$src2)>;
+def: Pat<(mul (Aext64 I32:$Rs), (Aext64 I32:$Rt)),
+ (M2_dpmpyuu_s0 I32:$Rs, I32:$Rt)>;
-def: Pat<(mul Sext64Ld:$src1, Sext64Ld:$src2),
- (M2_dpmpyss_s0 (LoReg DoubleRegs:$src1), (LoReg DoubleRegs:$src2))>;
+def: Pat<(mul Sext64:$Rs, Sext64:$Rt),
+ (M2_dpmpyss_s0 (LoReg Sext64:$Rs), (LoReg Sext64:$Rt))>;
// Multiply and accumulate, use full result.
// Rxx[+-]=mpy(Rs,Rt)
-def: Pat<(add I64:$src1, (mul (Sext64 I32:$src2), (Sext64 I32:$src3))),
- (M2_dpmpyss_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(add I64:$Rx, (mul Sext64:$Rs, Sext64:$Rt)),
+ (M2_dpmpyss_acc_s0 I64:$Rx, (LoReg Sext64:$Rs), (LoReg Sext64:$Rt))>;
-def: Pat<(sub I64:$src1, (mul (Sext64 I32:$src2), (Sext64 I32:$src3))),
- (M2_dpmpyss_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(sub I64:$Rx, (mul Sext64:$Rs, Sext64:$Rt)),
+ (M2_dpmpyss_nac_s0 I64:$Rx, (LoReg Sext64:$Rs), (LoReg Sext64:$Rt))>;
-def: Pat<(add I64:$src1, (mul (Aext64 I32:$src2), (Aext64 I32:$src3))),
- (M2_dpmpyuu_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(add I64:$Rx, (mul (Aext64 I32:$Rs), (Aext64 I32:$Rt))),
+ (M2_dpmpyuu_acc_s0 I64:$Rx, I32:$Rs, I32:$Rt)>;
-def: Pat<(add I64:$src1, (mul (Zext64 I32:$src2), (Zext64 I32:$src3))),
- (M2_dpmpyuu_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(add I64:$Rx, (mul (Zext64 I32:$Rs), (Zext64 I32:$Rt))),
+ (M2_dpmpyuu_acc_s0 I64:$Rx, I32:$Rs, I32:$Rt)>;
-def: Pat<(sub I64:$src1, (mul (Aext64 I32:$src2), (Aext64 I32:$src3))),
- (M2_dpmpyuu_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(sub I64:$Rx, (mul (Aext64 I32:$Rs), (Aext64 I32:$Rt))),
+ (M2_dpmpyuu_nac_s0 I64:$Rx, I32:$Rs, I32:$Rt)>;
-def: Pat<(sub I64:$src1, (mul (Zext64 I32:$src2), (Zext64 I32:$src3))),
- (M2_dpmpyuu_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(sub I64:$Rx, (mul (Zext64 I32:$Rs), (Zext64 I32:$Rt))),
+ (M2_dpmpyuu_nac_s0 I64:$Rx, I32:$Rs, I32:$Rt)>;
class Storepi_pat<PatFrag Store, PatFrag Value, PatFrag Offset,
InstHexagon MI>
@@ -545,7 +539,8 @@ def: Storexm_simple_pat<truncstorei8, I64, LoReg, S2_storerb_io>;
def: Storexm_simple_pat<truncstorei16, I64, LoReg, S2_storerh_io>;
def: Storexm_simple_pat<truncstorei32, I64, LoReg, S2_storeri_io>;
-def: Pat <(Sext64 I32:$src), (A2_sxtw I32:$src)>;
+def: Pat <(i64 (sext I32:$src)), (A2_sxtw I32:$src)>;
+def: Pat <(i64 (sext_inreg I64:$src, i32)), (A2_sxtw (LoReg I64:$src))>;
def: Pat<(select (i1 (setlt I32:$src, 0)), (sub 0, I32:$src), I32:$src),
(A2_abs IntRegs:$src)>;
@@ -1159,8 +1154,8 @@ multiclass MinMax_pats_p<PatFrag Op, InstHexagon Inst, InstHexagon SwapInst> {
defm: T_MinMax_pats<Op, I64, Inst, SwapInst>;
}
-def: Pat<(add (Sext64 I32:$Rs), I64:$Rt),
- (A2_addsp IntRegs:$Rs, DoubleRegs:$Rt)>;
+def: Pat<(add Sext64:$Rs, I64:$Rt),
+ (A2_addsp (LoReg Sext64:$Rs), DoubleRegs:$Rt)>;
let AddedComplexity = 200 in {
defm: MinMax_pats_p<setge, A2_maxp, A2_minp>;
diff --git a/lib/Target/Hexagon/HexagonTargetMachine.cpp b/lib/Target/Hexagon/HexagonTargetMachine.cpp
index 8e93df6201ae..14ecf297d351 100644
--- a/lib/Target/Hexagon/HexagonTargetMachine.cpp
+++ b/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -223,7 +223,7 @@ namespace {
/// Hexagon Code Generator Pass Configuration Options.
class HexagonPassConfig : public TargetPassConfig {
public:
- HexagonPassConfig(HexagonTargetMachine *TM, PassManagerBase &PM)
+ HexagonPassConfig(HexagonTargetMachine &TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {}
HexagonTargetMachine &getHexagonTargetMachine() const {
@@ -245,7 +245,7 @@ public:
} // namespace
TargetPassConfig *HexagonTargetMachine::createPassConfig(PassManagerBase &PM) {
- return new HexagonPassConfig(this, PM);
+ return new HexagonPassConfig(*this, PM);
}
void HexagonPassConfig::addIRPasses() {
diff --git a/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
index cd474921d4bc..fa08afe4019d 100644
--- a/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
+++ b/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
@@ -273,25 +273,17 @@ bool HexagonPacketizerList::isCallDependent(const MachineInstr &MI,
if (DepReg == HRI->getFrameRegister() || DepReg == HRI->getStackRegister())
return true;
- // Check if this is a predicate dependence.
- const TargetRegisterClass* RC = HRI->getMinimalPhysRegClass(DepReg);
- if (RC == &Hexagon::PredRegsRegClass)
- return true;
-
- // Assumes that the first operand of the CALLr is the function address.
- if (HII->isIndirectCall(MI) && (DepType == SDep::Data)) {
- const MachineOperand MO = MI.getOperand(0);
- if (MO.isReg() && MO.isUse() && (MO.getReg() == DepReg))
- return true;
+ // Call-like instructions can be packetized with preceding instructions
+ // that define registers implicitly used or modified by the call. Explicit
+ // uses are still prohibited, as in the case of indirect calls:
+ // r0 = ...
+ // J2_jumpr r0
+ if (DepType == SDep::Data) {
+ for (const MachineOperand MO : MI.operands())
+ if (MO.isReg() && MO.getReg() == DepReg && !MO.isImplicit())
+ return true;
}
- if (HII->isJumpR(MI)) {
- const MachineOperand &MO = HII->isPredicated(MI) ? MI.getOperand(1)
- : MI.getOperand(0);
- assert(MO.isReg() && MO.isUse());
- if (MO.getReg() == DepReg)
- return true;
- }
return false;
}
@@ -333,11 +325,13 @@ bool HexagonPacketizerList::isNewifiable(const MachineInstr &MI,
const TargetRegisterClass *NewRC) {
// Vector stores can be predicated, and can be new-value stores, but
// they cannot be predicated on a .new predicate value.
- if (NewRC == &Hexagon::PredRegsRegClass)
+ if (NewRC == &Hexagon::PredRegsRegClass) {
if (HII->isHVXVec(MI) && MI.mayStore())
return false;
- return HII->isCondInst(MI) || HII->isJumpR(MI) || MI.isReturn() ||
- HII->mayBeNewStore(MI);
+ return HII->isPredicated(MI) && HII->getDotNewPredOp(MI, nullptr) > 0;
+ }
+ // If the class is not PredRegs, it could only apply to new-value stores.
+ return HII->mayBeNewStore(MI);
}
// Promote an instructiont to its .cur form.
@@ -760,11 +754,14 @@ bool HexagonPacketizerList::canPromoteToNewValue(const MachineInstr &MI,
return false;
}
-static bool isImplicitDependency(const MachineInstr &I, unsigned DepReg) {
+static bool isImplicitDependency(const MachineInstr &I, bool CheckDef,
+ unsigned DepReg) {
for (auto &MO : I.operands()) {
- if (MO.isRegMask() && MO.clobbersPhysReg(DepReg))
+ if (CheckDef && MO.isRegMask() && MO.clobbersPhysReg(DepReg))
return true;
- if (MO.isReg() && MO.isDef() && (MO.getReg() == DepReg) && MO.isImplicit())
+ if (!MO.isReg() || MO.getReg() != DepReg || !MO.isImplicit())
+ continue;
+ if (CheckDef == MO.isDef())
return true;
}
return false;
@@ -798,7 +795,8 @@ bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr &MI,
// If dependency is trough an implicitly defined register, we should not
// newify the use.
- if (isImplicitDependency(PI, DepReg))
+ if (isImplicitDependency(PI, true, DepReg) ||
+ isImplicitDependency(MI, false, DepReg))
return false;
const MCInstrDesc& MCID = PI.getDesc();
@@ -808,8 +806,7 @@ bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr &MI,
// predicate .new
if (RC == &Hexagon::PredRegsRegClass)
- if (HII->isCondInst(MI) || HII->isJumpR(MI) || MI.isReturn())
- return HII->predCanBeUsedAsDotNew(PI, DepReg);
+ return HII->predCanBeUsedAsDotNew(PI, DepReg);
if (RC != &Hexagon::PredRegsRegClass && !HII->mayBeNewStore(MI))
return false;