From d760dbf10eeadcd54c76cfe2681c7eb82625434a Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 14 Feb 2018 20:46:06 +0000 Subject: [PATCH] [Hexagon] Split HVX vector pair loads/stores, expand unaligned loads llvm-svn: 325169 --- lib/Target/Hexagon/HexagonISelLowering.cpp | 11 ++ lib/Target/Hexagon/HexagonISelLowering.h | 5 + lib/Target/Hexagon/HexagonISelLoweringHVX.cpp | 137 ++++++++++++++++-- lib/Target/Hexagon/HexagonPatterns.td | 27 ---- lib/Target/Hexagon/HexagonPatternsHVX.td | 123 ++++++++++------ .../autohvx/isel-expand-unaligned-loads.ll | 26 ++++ test/CodeGen/Hexagon/select-instr-align.ll | 26 ++-- 7 files changed, 259 insertions(+), 96 deletions(-) create mode 100644 test/CodeGen/Hexagon/autohvx/isel-expand-unaligned-loads.ll diff --git a/lib/Target/Hexagon/HexagonISelLowering.cpp b/lib/Target/Hexagon/HexagonISelLowering.cpp index e0078221b5e..fd99a8fd0f0 100644 --- a/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -1727,6 +1727,7 @@ const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const { case HexagonISD::QTRUE: return "HexagonISD::QTRUE"; case HexagonISD::QFALSE: return "HexagonISD::QFALSE"; case HexagonISD::TYPECAST: return "HexagonISD::TYPECAST"; + case HexagonISD::VALIGNADDR: return "HexagonISD::VALIGNADDR"; case HexagonISD::OP_END: break; } return nullptr; @@ -1821,6 +1822,16 @@ HexagonTargetLowering::getPreferredVectorAction(EVT VT) const { return TargetLoweringBase::TypeSplitVector; } +std::pair +HexagonTargetLowering::getBaseAndOffset(SDValue Addr) const { + if (Addr.getOpcode() == ISD::ADD) { + SDValue Op1 = Addr.getOperand(1); + if (auto *CN = dyn_cast(Op1.getNode())) + return { Addr.getOperand(0), CN->getSExtValue() }; + } + return { Addr, 0 }; +} + // Lower a vector shuffle (V1, V2, V3). V1 and V2 are the two vectors // to select data from, V3 is the permutation. SDValue diff --git a/lib/Target/Hexagon/HexagonISelLowering.h b/lib/Target/Hexagon/HexagonISelLowering.h index a57acec8204..8ba08564547 100644 --- a/lib/Target/Hexagon/HexagonISelLowering.h +++ b/lib/Target/Hexagon/HexagonISelLowering.h @@ -79,6 +79,8 @@ namespace HexagonISD { VZERO, TYPECAST, // No-op that's used to convert between different legal // types in a register. + VALIGNADDR, // Align vector address: Op & -HwLen, except when it is + // an address in a vector load, then it's a no-op. OP_END }; @@ -299,6 +301,7 @@ namespace HexagonISD { private: void initializeHVXLowering(); + std::pair getBaseAndOffset(SDValue Addr) const; bool getBuildVectorConstInts(ArrayRef Values, MVT VecTy, SelectionDAG &DAG, @@ -415,8 +418,10 @@ namespace HexagonISD { SDValue LowerHvxSetCC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerHvxExtend(SDValue Op, SelectionDAG &DAG) const; SDValue LowerHvxShift(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerHvxUnalignedLoad(SDValue Op, SelectionDAG &DAG) const; SDValue SplitHvxPairOp(SDValue Op, SelectionDAG &DAG) const; + SDValue SplitHvxMemOp(SDValue Op, SelectionDAG &DAG) const; std::pair findRepresentativeClass(const TargetRegisterInfo *TRI, MVT VT) diff --git a/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp index 4b732171805..b9e285131b3 100644 --- a/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp +++ b/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp @@ -10,9 +10,14 @@ #include "HexagonISelLowering.h" #include "HexagonRegisterInfo.h" #include "HexagonSubtarget.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; +static cl::opt ExpandUnalignedLoads("hvx-expand-unaligned-loads", + cl::Hidden, cl::init(true), + cl::desc("Expand unaligned HVX loads into a pair of aligned loads")); + static const MVT LegalV64[] = { MVT::v64i8, MVT::v32i16, MVT::v16i32 }; static const MVT LegalW64[] = { MVT::v128i8, MVT::v64i16, MVT::v32i32 }; static const MVT LegalV128[] = { MVT::v128i8, MVT::v64i16, MVT::v32i32 }; @@ -83,6 +88,7 @@ HexagonTargetLowering::initializeHVXLowering() { setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, T, Legal); } + setOperationAction(ISD::LOAD, T, Custom); setOperationAction(ISD::MUL, T, Custom); setOperationAction(ISD::MULHS, T, Custom); setOperationAction(ISD::MULHU, T, Custom); @@ -151,6 +157,9 @@ HexagonTargetLowering::initializeHVXLowering() { setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, T, Legal); setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, T, Legal); + setOperationAction(ISD::LOAD, T, Custom); + setOperationAction(ISD::STORE, T, Custom); + setOperationAction(ISD::ADD, T, Legal); setOperationAction(ISD::SUB, T, Legal); setOperationAction(ISD::MUL, T, Custom); @@ -1286,6 +1295,59 @@ HexagonTargetLowering::LowerHvxShift(SDValue Op, SelectionDAG &DAG) const { return Op; } +SDValue +HexagonTargetLowering::LowerHvxUnalignedLoad(SDValue Op, SelectionDAG &DAG) + const { + LoadSDNode *LN = cast(Op.getNode()); + unsigned HaveAlign = LN->getAlignment(); + MVT VecTy = ty(Op); + Type *Ty = EVT(VecTy).getTypeForEVT(*DAG.getContext()); + const DataLayout &DL = DAG.getDataLayout(); + unsigned NeedAlign = DL.getABITypeAlignment(Ty); + if (HaveAlign >= NeedAlign || !ExpandUnalignedLoads) + return Op; + + unsigned HwLen = Subtarget.getVectorLength(); + + SDValue Base = LN->getBasePtr(); + SDValue Chain = LN->getChain(); + auto BO = getBaseAndOffset(Base); + unsigned BaseOpc = BO.first.getOpcode(); + if (BaseOpc == HexagonISD::VALIGNADDR && BO.second % HwLen == 0) + return Op; + + const SDLoc &dl(Op); + if (BO.second % HwLen != 0) { + BO.first = DAG.getNode(ISD::ADD, dl, MVT::i32, BO.first, + DAG.getConstant(BO.second % HwLen, dl, MVT::i32)); + BO.second -= BO.second % HwLen; + } + SDValue BaseNoOff = (BaseOpc != HexagonISD::VALIGNADDR) + ? DAG.getNode(HexagonISD::VALIGNADDR, dl, MVT::i32, BO.first) + : BO.first; + SDValue Base0 = DAG.getMemBasePlusOffset(BaseNoOff, BO.second, dl); + SDValue Base1 = DAG.getMemBasePlusOffset(BaseNoOff, BO.second+HwLen, dl); + + MachineMemOperand *WideMMO = nullptr; + if (MachineMemOperand *MMO = LN->getMemOperand()) { + MachineFunction &MF = DAG.getMachineFunction(); + WideMMO = MF.getMachineMemOperand(MMO->getPointerInfo(), MMO->getFlags(), + 2*HwLen, HwLen, MMO->getAAInfo(), MMO->getRanges(), + MMO->getSyncScopeID(), MMO->getOrdering(), + MMO->getFailureOrdering()); + } + + SDValue Load0 = DAG.getLoad(VecTy, dl, Chain, Base0, WideMMO); + SDValue Load1 = DAG.getLoad(VecTy, dl, Chain, Base1, WideMMO); + + SDValue Aligned = getInstr(Hexagon::V6_valignb, dl, VecTy, + {Load1, Load0, BaseNoOff.getOperand(0)}, DAG); + 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::SplitHvxPairOp(SDValue Op, SelectionDAG &DAG) const { assert(!Op.isMachineOpcode()); @@ -1319,6 +1381,49 @@ HexagonTargetLowering::SplitHvxPairOp(SDValue Op, SelectionDAG &DAG) const { return S; } +SDValue +HexagonTargetLowering::SplitHvxMemOp(SDValue Op, SelectionDAG &DAG) const { + LSBaseSDNode *BN = cast(Op.getNode()); + assert(BN->isUnindexed()); + MVT MemTy = BN->getMemoryVT().getSimpleVT(); + if (!isHvxPairTy(MemTy)) + return Op; + + const SDLoc &dl(Op); + unsigned HwLen = Subtarget.getVectorLength(); + MVT SingleTy = typeSplit(MemTy).first; + SDValue Chain = BN->getChain(); + SDValue Base0 = BN->getBasePtr(); + SDValue Base1 = DAG.getMemBasePlusOffset(Base0, HwLen, dl); + + MachineMemOperand *MOp0 = nullptr, *MOp1 = nullptr; + if (MachineMemOperand *MMO = BN->getMemOperand()) { + MachineFunction &MF = DAG.getMachineFunction(); + MOp0 = MF.getMachineMemOperand(MMO, 0, HwLen); + MOp1 = MF.getMachineMemOperand(MMO, HwLen, HwLen); + } + + unsigned MemOpc = BN->getOpcode(); + SDValue NewOp; + + if (MemOpc == ISD::LOAD) { + SDValue Load0 = DAG.getLoad(SingleTy, dl, Chain, Base0, MOp0); + SDValue Load1 = DAG.getLoad(SingleTy, dl, Chain, Base1, MOp1); + NewOp = DAG.getMergeValues( + { DAG.getNode(ISD::CONCAT_VECTORS, dl, MemTy, Load0, Load1), + DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + Load0.getValue(1), Load1.getValue(1)) }, dl); + } else { + assert(MemOpc == ISD::STORE); + VectorPair Vals = opSplit(cast(Op)->getValue(), dl, DAG); + SDValue Store0 = DAG.getStore(Chain, dl, Vals.first, Base0, MOp0); + SDValue Store1 = DAG.getStore(Chain, dl, Vals.second, Base1, MOp1); + NewOp = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store0, Store1); + } + + return NewOp; +} + SDValue HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); @@ -1331,6 +1436,9 @@ HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const { switch (Opc) { default: break; + case ISD::LOAD: + case ISD::STORE: + return SplitHvxMemOp(Op, DAG); case ISD::MUL: case ISD::MULHS: case ISD::MULHU: @@ -1350,25 +1458,26 @@ HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const { switch (Opc) { default: break; - case ISD::BUILD_VECTOR: return LowerHvxBuildVector(Op, DAG); - case ISD::CONCAT_VECTORS: return LowerHvxConcatVectors(Op, DAG); - case ISD::INSERT_SUBVECTOR: return LowerHvxInsertSubvector(Op, DAG); - case ISD::INSERT_VECTOR_ELT: return LowerHvxInsertElement(Op, DAG); - case ISD::EXTRACT_SUBVECTOR: return LowerHvxExtractSubvector(Op, DAG); - case ISD::EXTRACT_VECTOR_ELT: return LowerHvxExtractElement(Op, DAG); + case ISD::BUILD_VECTOR: return LowerHvxBuildVector(Op, DAG); + case ISD::CONCAT_VECTORS: return LowerHvxConcatVectors(Op, DAG); + case ISD::INSERT_SUBVECTOR: return LowerHvxInsertSubvector(Op, DAG); + case ISD::INSERT_VECTOR_ELT: return LowerHvxInsertElement(Op, DAG); + case ISD::EXTRACT_SUBVECTOR: return LowerHvxExtractSubvector(Op, DAG); + case ISD::EXTRACT_VECTOR_ELT: return LowerHvxExtractElement(Op, DAG); - case ISD::ANY_EXTEND: return LowerHvxAnyExt(Op, DAG); - case ISD::SIGN_EXTEND: return LowerHvxSignExt(Op, DAG); - case ISD::ZERO_EXTEND: return LowerHvxZeroExt(Op, DAG); + case ISD::LOAD: return LowerHvxUnalignedLoad(Op, DAG); + case ISD::ANY_EXTEND: return LowerHvxAnyExt(Op, DAG); + case ISD::SIGN_EXTEND: return LowerHvxSignExt(Op, DAG); + case ISD::ZERO_EXTEND: return LowerHvxZeroExt(Op, DAG); case ISD::SRA: case ISD::SHL: - case ISD::SRL: return LowerHvxShift(Op, DAG); - case ISD::MUL: return LowerHvxMul(Op, DAG); + case ISD::SRL: return LowerHvxShift(Op, DAG); + case ISD::MUL: return LowerHvxMul(Op, DAG); case ISD::MULHS: - case ISD::MULHU: return LowerHvxMulh(Op, DAG); - case ISD::ANY_EXTEND_VECTOR_INREG: return LowerHvxExtend(Op, DAG); + case ISD::MULHU: return LowerHvxMulh(Op, DAG); + case ISD::ANY_EXTEND_VECTOR_INREG: return LowerHvxExtend(Op, DAG); case ISD::SETCC: - case ISD::INTRINSIC_VOID: return Op; + case ISD::INTRINSIC_VOID: return Op; } #ifndef NDEBUG Op.dumpr(&DAG); diff --git a/lib/Target/Hexagon/HexagonPatterns.td b/lib/Target/Hexagon/HexagonPatterns.td index 6559881c59f..70969e283c0 100644 --- a/lib/Target/Hexagon/HexagonPatterns.td +++ b/lib/Target/Hexagon/HexagonPatterns.td @@ -109,16 +109,6 @@ def IsOrAdd: PatFrag<(ops node:$A, node:$B), (or node:$A, node:$B), [{ return isOrEquivalentToAdd(N); }]>; -def IsVecOff : PatLeaf<(i32 imm), [{ - int32_t V = N->getSExtValue(); - int32_t VecSize = HRI->getSpillSize(Hexagon::HvxVRRegClass); - assert(isPowerOf2_32(VecSize)); - if ((uint32_t(V) & (uint32_t(VecSize)-1)) != 0) - return false; - int32_t L = Log2_32(VecSize); - return isInt<4>(V >> L); -}]>; - def IsPow2_32: PatLeaf<(i32 imm), [{ uint32_t V = N->getZExtValue(); return isPowerOf2_32(V); @@ -249,23 +239,6 @@ def: Pat<(IsOrAdd (i32 AddrFI:$Rs), s32_0ImmPred:$off), (PS_fi (i32 AddrFI:$Rs), imm:$off)>; -def alignedload: PatFrag<(ops node:$a), (load $a), [{ - return isAlignedMemNode(dyn_cast(N)); -}]>; - -def unalignedload: PatFrag<(ops node:$a), (load $a), [{ - return !isAlignedMemNode(dyn_cast(N)); -}]>; - -def alignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{ - return isAlignedMemNode(dyn_cast(N)); -}]>; - -def unalignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{ - return !isAlignedMemNode(dyn_cast(N)); -}]>; - - // Converters from unary/binary SDNode to PatFrag. class pf1 : PatFrag<(ops node:$a), (Op node:$a)>; class pf2 : PatFrag<(ops node:$a, node:$b), (Op node:$a, node:$b)>; diff --git a/lib/Target/Hexagon/HexagonPatternsHVX.td b/lib/Target/Hexagon/HexagonPatternsHVX.td index 50081799bf7..a3dc8d3dabc 100644 --- a/lib/Target/Hexagon/HexagonPatternsHVX.td +++ b/lib/Target/Hexagon/HexagonPatternsHVX.td @@ -16,6 +16,12 @@ def HwLen2: SDNodeXFormgetTargetConstant(ST.getVectorLength()/2, SDLoc(N), MVT::i32); }]>; +def NHwLen: SDNodeXForm(CurDAG->getSubtarget()); + return CurDAG->getTargetConstant(-int(ST.getVectorLength()), SDLoc(N), + MVT::i32); +}]>; + def Q2V: OutPatFrag<(ops node:$Qs), (V6_vandqrt $Qs, (A2_tfrsi -1))>; def Combinev: OutPatFrag<(ops node:$Vs, node:$Vt), @@ -32,10 +38,12 @@ def Combineq: OutPatFrag<(ops node:$Qs, node:$Qt), def LoVec: OutPatFrag<(ops node:$Vs), (EXTRACT_SUBREG $Vs, vsub_lo)>; def HiVec: OutPatFrag<(ops node:$Vs), (EXTRACT_SUBREG $Vs, vsub_hi)>; -def HexagonVZERO: SDNode<"HexagonISD::VZERO", SDTVecLeaf>; -def HexagonQCAT: SDNode<"HexagonISD::QCAT", SDTVecBinOp>; -def HexagonQTRUE: SDNode<"HexagonISD::QTRUE", SDTVecLeaf>; -def HexagonQFALSE: SDNode<"HexagonISD::QFALSE", SDTVecLeaf>; +def HexagonVZERO: SDNode<"HexagonISD::VZERO", SDTVecLeaf>; +def HexagonQCAT: SDNode<"HexagonISD::QCAT", SDTVecBinOp>; +def HexagonQTRUE: SDNode<"HexagonISD::QTRUE", SDTVecLeaf>; +def HexagonQFALSE: SDNode<"HexagonISD::QFALSE", SDTVecLeaf>; +def HexagonVALIGNADDR: SDNode<"HexagonISD::VALIGNADDR", SDTIntUnaryOp>; + def vzero: PatFrag<(ops), (HexagonVZERO)>; def qtrue: PatFrag<(ops), (HexagonQTRUE)>; def qfalse: PatFrag<(ops), (HexagonQFALSE)>; @@ -43,6 +51,7 @@ def qcat: PatFrag<(ops node:$Qs, node:$Qt), (HexagonQCAT node:$Qs, node:$Qt)>; def qnot: PatFrag<(ops node:$Qs), (xor node:$Qs, qtrue)>; +def valignaddr: PatFrag<(ops node:$Addr), (HexagonVALIGNADDR node:$Addr)>; def VSxtb: OutPatFrag<(ops node:$Vs), (V6_vunpackb $Vs)>; def VSxth: OutPatFrag<(ops node:$Vs), (V6_vunpackh $Vs)>; @@ -62,41 +71,75 @@ def SplatH: SDNodeXFormgetTargetConstant(V << 16 | V, SDLoc(N), MVT::i32); }]>; +def IsVecOff : PatLeaf<(i32 imm), [{ + int32_t V = N->getSExtValue(); + int32_t VecSize = HRI->getSpillSize(Hexagon::HvxVRRegClass); + assert(isPowerOf2_32(VecSize)); + if ((uint32_t(V) & (uint32_t(VecSize)-1)) != 0) + return false; + int32_t L = Log2_32(VecSize); + return isInt<4>(V >> L); +}]>; + + +def alignedload: PatFrag<(ops node:$a), (load $a), [{ + return isAlignedMemNode(dyn_cast(N)); +}]>; + +def unalignedload: PatFrag<(ops node:$a), (load $a), [{ + return !isAlignedMemNode(dyn_cast(N)); +}]>; + +def alignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{ + return isAlignedMemNode(dyn_cast(N)); +}]>; + +def unalignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{ + return !isAlignedMemNode(dyn_cast(N)); +}]>; + // HVX loads -multiclass HvxLd_pat { - def: Pat<(VT (Load I32:$Rt)), (MI I32:$Rt, 0)>; - def: Pat<(VT (Load (add I32:$Rt, ImmPred:$s))), (MI I32:$Rt, imm:$s)>; + def: Pat<(ResType (Load I32:$Rt)), + (MI I32:$Rt, 0)>; + def: Pat<(ResType (Load (add I32:$Rt, ImmPred:$s))), + (MI I32:$Rt, imm:$s)>; // The HVX selection code for shuffles can generate vector constants. // Calling "Select" on the resulting loads from CP fails without these // patterns. - def: Pat<(VT (Load (HexagonCP tconstpool:$A))), (MI (A2_tfrsi imm:$A), 0)>; - def: Pat<(VT (Load (HexagonAtPcrel tconstpool:$A))), + def: Pat<(ResType (Load (HexagonCP tconstpool:$A))), + (MI (A2_tfrsi imm:$A), 0)>; + def: Pat<(ResType (Load (HexagonAtPcrel tconstpool:$A))), (MI (C4_addipc imm:$A), 0)>; } -let Predicates = [UseHVX] in { - multiclass HvxLdVs_pat { - defm: HvxLd_pat; - defm: HvxLd_pat; - defm: HvxLd_pat; +multiclass HvxLda_pat { + let AddedComplexity = 50 in { + def: Pat<(ResType (Load (valignaddr I32:$Rt))), + (MI I32:$Rt, 0)>; + def: Pat<(ResType (Load (add (valignaddr I32:$Rt), ImmPred:$Off))), + (MI I32:$Rt, imm:$Off)>; } - defm: HvxLdVs_pat; - defm: HvxLdVs_pat; - defm: HvxLdVs_pat; - - multiclass HvxLdWs_pat { - defm: HvxLd_pat; - defm: HvxLd_pat; - defm: HvxLd_pat; - } - defm: HvxLdWs_pat; - defm: HvxLdWs_pat; - defm: HvxLdWs_pat; + defm: HvxLd_pat; } +let Predicates = [UseHVX] in { + defm: HvxLda_pat; + defm: HvxLda_pat; + defm: HvxLda_pat; + + defm: HvxLda_pat; + defm: HvxLda_pat; + defm: HvxLda_pat; + + defm: HvxLd_pat; + defm: HvxLd_pat; + defm: HvxLd_pat; +} // HVX stores @@ -109,23 +152,17 @@ multiclass HvxSt_pat { - defm: HvxSt_pat; - defm: HvxSt_pat; - defm: HvxSt_pat; - } - defm: HvxStVs_pat; - defm: HvxStVs_pat; - defm: HvxStVs_pat; + defm: HvxSt_pat; + defm: HvxSt_pat; + defm: HvxSt_pat; - multiclass HvxStWs_pat { - defm: HvxSt_pat; - defm: HvxSt_pat; - defm: HvxSt_pat; - } - defm: HvxStWs_pat; - defm: HvxStWs_pat; - defm: HvxStWs_pat; + defm: HvxSt_pat; + defm: HvxSt_pat; + defm: HvxSt_pat; + + defm: HvxSt_pat; + defm: HvxSt_pat; + defm: HvxSt_pat; } @@ -138,6 +175,8 @@ let Predicates = [UseHVX] in { def: Pat<(VecPI16 vzero), (Combinev (V6_vd0), (V6_vd0))>; def: Pat<(VecPI32 vzero), (Combinev (V6_vd0), (V6_vd0))>; + def: Pat<(valignaddr I32:$Rs), (A2_andir I32:$Rs, (NHwLen (i32 0)))>; + def: Pat<(VecPI8 (concat_vectors HVI8:$Vs, HVI8:$Vt)), (Combinev HvxVR:$Vt, HvxVR:$Vs)>; def: Pat<(VecPI16 (concat_vectors HVI16:$Vs, HVI16:$Vt)), diff --git a/test/CodeGen/Hexagon/autohvx/isel-expand-unaligned-loads.ll b/test/CodeGen/Hexagon/autohvx/isel-expand-unaligned-loads.ll new file mode 100644 index 00000000000..5494bd84fcc --- /dev/null +++ b/test/CodeGen/Hexagon/autohvx/isel-expand-unaligned-loads.ll @@ -0,0 +1,26 @@ +; RUN: llc -march=hexagon -disable-packetizer < %s | FileCheck %s + +; CHECK-LABEL: test_00: +; CHECK-DAG: v[[V00:[0-9]+]] = vmem(r[[B00:[0-9]+]]+#0) +; CHECK-DAG: v[[V01:[0-9]+]] = vmem(r[[B00]]+#1) +; CHECK: valign(v[[V01]],v[[V00]],r[[B00]]) +define void @test_00(<64 x i8>* %p, <64 x i8>* %q) #0 { + %v0 = load <64 x i8>, <64 x i8>* %p, align 1 + store <64 x i8> %v0, <64 x i8>* %q, align 1 + ret void +} + +; CHECK-LABEL: test_01: +; CHECK-DAG: v[[V10:[0-9]+]] = vmem(r[[B01:[0-9]+]]+#0) +; CHECK-DAG: v[[V11:[0-9]+]] = vmem(r[[B01]]+#1) +; CHECK-DAG: v[[V12:[0-9]+]] = vmem(r[[B01]]+#2) +; CHECK: } +; CHECK-DAG: valign(v[[V11]],v[[V10]],r[[B01]]) +; CHECK-DAG: valign(v[[V12]],v[[V11]],r[[B01]]) +define void @test_01(<128 x i8>* %p, <128 x i8>* %q) #0 { + %v0 = load <128 x i8>, <128 x i8>* %p, align 1 + store <128 x i8> %v0, <128 x i8>* %q, align 1 + ret void +} + +attributes #0 = { nounwind "target-cpu"="hexagonv60" "target-features"="+hvx,+hvx-length64b" } diff --git a/test/CodeGen/Hexagon/select-instr-align.ll b/test/CodeGen/Hexagon/select-instr-align.ll index 368ee3c5726..9d8939282c6 100644 --- a/test/CodeGen/Hexagon/select-instr-align.ll +++ b/test/CodeGen/Hexagon/select-instr-align.ll @@ -1,31 +1,31 @@ -; RUN: llc -march=hexagon -mcpu=hexagonv60 -mattr=+hvxv60,hvx-length64b < %s | FileCheck %s +; RUN: llc -march=hexagon -hvx-expand-unaligned-loads=0 < %s | FileCheck %s + ; CHECK-LABEL: aligned_load: ; CHECK: = vmem({{.*}}) -; CHECK-LABEL: aligned_store: -; CHECK: vmem({{.*}}) = -; CHECK-LABEL: unaligned_load: -; CHECK: = vmemu({{.*}}) -; CHECK-LABEL: unaligned_store: -; CHECK: vmemu({{.*}}) = - -define <16 x i32> @aligned_load(<16 x i32>* %p, <16 x i32> %a) { +define <16 x i32> @aligned_load(<16 x i32>* %p, <16 x i32> %a) #0 { %v = load <16 x i32>, <16 x i32>* %p, align 64 ret <16 x i32> %v } -define void @aligned_store(<16 x i32>* %p, <16 x i32> %a) { +; CHECK-LABEL: aligned_store: +; CHECK: vmem({{.*}}) = +define void @aligned_store(<16 x i32>* %p, <16 x i32> %a) #0 { store <16 x i32> %a, <16 x i32>* %p, align 64 ret void } -define <16 x i32> @unaligned_load(<16 x i32>* %p, <16 x i32> %a) { +; CHECK-LABEL: unaligned_load: +; CHECK: = vmemu({{.*}}) +define <16 x i32> @unaligned_load(<16 x i32>* %p, <16 x i32> %a) #0 { %v = load <16 x i32>, <16 x i32>* %p, align 32 ret <16 x i32> %v } -define void @unaligned_store(<16 x i32>* %p, <16 x i32> %a) { +; CHECK-LABEL: unaligned_store: +; CHECK: vmemu({{.*}}) = +define void @unaligned_store(<16 x i32>* %p, <16 x i32> %a) #0 { store <16 x i32> %a, <16 x i32>* %p, align 32 ret void } - +attributes #0 = { nounwind "target-cpu"="hexagonv60" "target-features"="+hvxv60,+hvx-length64b" }