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:
parent
f687ed1ec6
commit
d760dbf10e
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)>;
|
||||
|
@ -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)),
|
||||
|
26
test/CodeGen/Hexagon/autohvx/isel-expand-unaligned-loads.ll
Normal file
26
test/CodeGen/Hexagon/autohvx/isel-expand-unaligned-loads.ll
Normal 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" }
|
@ -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" }
|
||||
|
Loading…
Reference in New Issue
Block a user