1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

[Hexagon] Split HVX vector pair loads/stores, expand unaligned loads

llvm-svn: 325169
This commit is contained in:
Krzysztof Parzyszek 2018-02-14 20:46:06 +00:00
parent f687ed1ec6
commit d760dbf10e
7 changed files with 259 additions and 96 deletions

View File

@ -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<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 };
}
// Lower a vector shuffle (V1, V2, V3). V1 and V2 are the two vectors
// to select data from, V3 is the permutation.
SDValue

View File

@ -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<SDValue,int> getBaseAndOffset(SDValue Addr) const;
bool getBuildVectorConstInts(ArrayRef<SDValue> 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<const TargetRegisterClass*, uint8_t>
findRepresentativeClass(const TargetRegisterInfo *TRI, MVT VT)

View File

@ -10,9 +10,14 @@
#include "HexagonISelLowering.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
static cl::opt<bool> 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<LoadSDNode>(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<LSBaseSDNode>(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<StoreSDNode>(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);

View File

@ -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<MemSDNode>(N));
}]>;
def unalignedload: PatFrag<(ops node:$a), (load $a), [{
return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
}]>;
def alignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{
return isAlignedMemNode(dyn_cast<MemSDNode>(N));
}]>;
def unalignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{
return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
}]>;
// Converters from unary/binary SDNode to PatFrag.
class pf1<SDNode Op> : PatFrag<(ops node:$a), (Op node:$a)>;
class pf2<SDNode Op> : PatFrag<(ops node:$a, node:$b), (Op node:$a, node:$b)>;

View File

@ -16,6 +16,12 @@ def HwLen2: SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(ST.getVectorLength()/2, SDLoc(N), MVT::i32);
}]>;
def NHwLen: SDNodeXForm<imm, [{
const auto &ST = static_cast<const HexagonSubtarget&>(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: SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(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<MemSDNode>(N));
}]>;
def unalignedload: PatFrag<(ops node:$a), (load $a), [{
return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
}]>;
def alignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{
return isAlignedMemNode(dyn_cast<MemSDNode>(N));
}]>;
def unalignedstore: PatFrag<(ops node:$v, node:$a), (store $v, $a), [{
return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
}]>;
// HVX loads
multiclass HvxLd_pat<InstHexagon MI, PatFrag Load, ValueType VT,
multiclass HvxLd_pat<InstHexagon MI, PatFrag Load, ValueType ResType,
PatFrag ImmPred> {
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<InstHexagon MI, PatFrag Load> {
defm: HvxLd_pat<MI, Load, VecI8, IsVecOff>;
defm: HvxLd_pat<MI, Load, VecI16, IsVecOff>;
defm: HvxLd_pat<MI, Load, VecI32, IsVecOff>;
multiclass HvxLda_pat<InstHexagon MI, PatFrag Load, ValueType ResType,
PatFrag ImmPred> {
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<V6_vL32b_nt_ai, alignednontemporalload>;
defm: HvxLdVs_pat<V6_vL32b_ai, alignedload>;
defm: HvxLdVs_pat<V6_vL32Ub_ai, unalignedload>;
multiclass HvxLdWs_pat<InstHexagon MI, PatFrag Load> {
defm: HvxLd_pat<MI, Load, VecPI8, IsVecOff>;
defm: HvxLd_pat<MI, Load, VecPI16, IsVecOff>;
defm: HvxLd_pat<MI, Load, VecPI32, IsVecOff>;
}
defm: HvxLdWs_pat<PS_vloadrw_nt_ai, alignednontemporalload>;
defm: HvxLdWs_pat<PS_vloadrw_ai, alignedload>;
defm: HvxLdWs_pat<PS_vloadrwu_ai, unalignedload>;
defm: HvxLd_pat<MI, Load, ResType, ImmPred>;
}
let Predicates = [UseHVX] in {
defm: HvxLda_pat<V6_vL32b_nt_ai, alignednontemporalload, VecI8, IsVecOff>;
defm: HvxLda_pat<V6_vL32b_nt_ai, alignednontemporalload, VecI16, IsVecOff>;
defm: HvxLda_pat<V6_vL32b_nt_ai, alignednontemporalload, VecI32, IsVecOff>;
defm: HvxLda_pat<V6_vL32b_ai, alignedload, VecI8, IsVecOff>;
defm: HvxLda_pat<V6_vL32b_ai, alignedload, VecI16, IsVecOff>;
defm: HvxLda_pat<V6_vL32b_ai, alignedload, VecI32, IsVecOff>;
defm: HvxLd_pat<V6_vL32Ub_ai, unalignedload, VecI8, IsVecOff>;
defm: HvxLd_pat<V6_vL32Ub_ai, unalignedload, VecI16, IsVecOff>;
defm: HvxLd_pat<V6_vL32Ub_ai, unalignedload, VecI32, IsVecOff>;
}
// HVX stores
@ -109,23 +152,17 @@ multiclass HvxSt_pat<InstHexagon MI, PatFrag Store, PatFrag ImmPred,
}
let Predicates = [UseHVX] in {
multiclass HvxStVs_pat<InstHexagon MI, PatFrag Store> {
defm: HvxSt_pat<MI, Store, IsVecOff, HVI8>;
defm: HvxSt_pat<MI, Store, IsVecOff, HVI16>;
defm: HvxSt_pat<MI, Store, IsVecOff, HVI32>;
}
defm: HvxStVs_pat<V6_vS32b_nt_ai, alignednontemporalstore>;
defm: HvxStVs_pat<V6_vS32b_ai, alignedstore>;
defm: HvxStVs_pat<V6_vS32Ub_ai, unalignedstore>;
defm: HvxSt_pat<V6_vS32b_nt_ai, alignednontemporalstore, IsVecOff, HVI8>;
defm: HvxSt_pat<V6_vS32b_nt_ai, alignednontemporalstore, IsVecOff, HVI16>;
defm: HvxSt_pat<V6_vS32b_nt_ai, alignednontemporalstore, IsVecOff, HVI32>;
multiclass HvxStWs_pat<InstHexagon MI, PatFrag Store> {
defm: HvxSt_pat<MI, Store, IsVecOff, HWI8>;
defm: HvxSt_pat<MI, Store, IsVecOff, HWI16>;
defm: HvxSt_pat<MI, Store, IsVecOff, HWI32>;
}
defm: HvxStWs_pat<PS_vstorerw_nt_ai, alignednontemporalstore>;
defm: HvxStWs_pat<PS_vstorerw_ai, alignedstore>;
defm: HvxStWs_pat<PS_vstorerwu_ai, unalignedstore>;
defm: HvxSt_pat<V6_vS32b_ai, alignedstore, IsVecOff, HVI8>;
defm: HvxSt_pat<V6_vS32b_ai, alignedstore, IsVecOff, HVI16>;
defm: HvxSt_pat<V6_vS32b_ai, alignedstore, IsVecOff, HVI32>;
defm: HvxSt_pat<V6_vS32Ub_ai, unalignedstore, IsVecOff, HVI8>;
defm: HvxSt_pat<V6_vS32Ub_ai, unalignedstore, IsVecOff, HVI16>;
defm: HvxSt_pat<V6_vS32Ub_ai, unalignedstore, IsVecOff, HVI32>;
}
@ -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)),

View File

@ -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" }

View File

@ -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" }