summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
diff options
context:
space:
mode:
authorKrzysztof Parzyszek <kparzysz@codeaurora.org>2017-05-30 17:47:51 +0000
committerKrzysztof Parzyszek <kparzysz@codeaurora.org>2017-05-30 17:47:51 +0000
commitef58017b35b2fb5e20f08a247b861b046e5b3e75 (patch)
tree9ef26c3cb5f3593ac9ea7024c87a0cdd9e1318a4 /llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
parent591312c5c1a133949285dde012d8cf373ab31b12 (diff)
downloadbcm5719-llvm-ef58017b35b2fb5e20f08a247b861b046e5b3e75.tar.gz
bcm5719-llvm-ef58017b35b2fb5e20f08a247b861b046e5b3e75.zip
[Hexagon] Improve code generation for 32x32-bit multiplication
For multiplications of 64-bit values (giving 64-bit result), detect cases where the arguments are sign-extended 32-bit values, on a per- operand basis. This will allow few patterns to match a wider variety of combinations in which extensions can occur. llvm-svn: 304223
Diffstat (limited to 'llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp')
-rw-r--r--llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp189
1 files changed, 87 insertions, 102 deletions
diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
index 8e10c521a77..e4434136bf8 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
+++ b/llvm/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;
}
OpenPOWER on IntegriCloud