Skip to content

Commit

Permalink
[Codegen][ARM] Add addressing modes from masked loads and stores
Browse files Browse the repository at this point in the history
MVE has a basic symmetry between it's normal loads/store operations and
the masked variants. This means that masked loads and stores can use
pre-inc and post-inc addressing modes, just like the standard loads and
stores already do.

To enable that, this patch adds all the relevant infrastructure for
treating masked loads/stores addressing modes in the same way as normal
loads/stores.

This involves:
- Adding an AddressingMode to MaskedLoadStoreSDNode, along with an extra
   Offset operand that is added after the PtrBase.
- Extending the IndexedModeActions from 8bits to 16bits to store the
   legality of masked operations as well as normal ones. This array is
   fairly small, so doubling the size still won't make it very large.
   Offset masked loads can then be controlled with
   setIndexedMaskedLoadAction, similar to standard loads.
- The same methods that combine to indexed loads, such as
   CombineToPostIndexedLoadStore, are adjusted to handle masked loads in
   the same way.
- The ARM backend is then adjusted to make use of these indexed masked
   loads/stores.
- The X86 backend is adjusted to hopefully be no functional changes.

Differential Revision: https://reviews.llvm.org/D70176
  • Loading branch information
davemgreen committed Nov 26, 2019
1 parent 549db74 commit b5315ae
Show file tree
Hide file tree
Showing 25 changed files with 907 additions and 749 deletions.
19 changes: 12 additions & 7 deletions llvm/include/llvm/CodeGen/SelectionDAG.h
Expand Up @@ -1136,14 +1136,19 @@ class SelectionDAG {
/// Returns sum of the base pointer and offset.
SDValue getMemBasePlusOffset(SDValue Base, unsigned Offset, const SDLoc &DL);

SDValue getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr,
SDValue Mask, SDValue Src0, EVT MemVT,
MachineMemOperand *MMO, ISD::LoadExtType,
bool IsExpanding = false);
SDValue getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Base,
SDValue Offset, SDValue Mask, SDValue Src0, EVT MemVT,
MachineMemOperand *MMO, ISD::MemIndexedMode AM,
ISD::LoadExtType, bool IsExpanding = false);
SDValue getIndexedMaskedLoad(SDValue OrigLoad, const SDLoc &dl, SDValue Base,
SDValue Offset, ISD::MemIndexedMode AM);
SDValue getMaskedStore(SDValue Chain, const SDLoc &dl, SDValue Val,
SDValue Ptr, SDValue Mask, EVT MemVT,
MachineMemOperand *MMO, bool IsTruncating = false,
bool IsCompressing = false);
SDValue Base, SDValue Offset, SDValue Mask, EVT MemVT,
MachineMemOperand *MMO, ISD::MemIndexedMode AM,
bool IsTruncating = false, bool IsCompressing = false);
SDValue getIndexedMaskedStore(SDValue OrigStore, const SDLoc &dl,
SDValue Base, SDValue Offset,
ISD::MemIndexedMode AM);
SDValue getMaskedGather(SDVTList VTs, EVT VT, const SDLoc &dl,
ArrayRef<SDValue> Ops, MachineMemOperand *MMO,
ISD::MemIndexType IndexType);
Expand Down
53 changes: 38 additions & 15 deletions llvm/include/llvm/CodeGen/SelectionDAGNodes.h
Expand Up @@ -553,13 +553,15 @@ BEGIN_TWO_BYTE_PACK()

class LSBaseSDNodeBitfields {
friend class LSBaseSDNode;
friend class MaskedLoadStoreSDNode;
friend class MaskedGatherScatterSDNode;

uint16_t : NumMemSDNodeBits;

// This storage is shared between disparate class hierarchies to hold an
// enumeration specific to the class hierarchy in use.
// LSBaseSDNode => enum ISD::MemIndexedMode
// MaskedLoadStoreBaseSDNode => enum ISD::MemIndexedMode
// MaskedGatherScatterSDNode => enum ISD::MemIndexType
uint16_t AddressingMode : 3;
};
Expand Down Expand Up @@ -2273,19 +2275,38 @@ class MaskedLoadStoreSDNode : public MemSDNode {
friend class SelectionDAG;

MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order,
const DebugLoc &dl, SDVTList VTs, EVT MemVT,
const DebugLoc &dl, SDVTList VTs,
ISD::MemIndexedMode AM, EVT MemVT,
MachineMemOperand *MMO)
: MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {}
: MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {
LSBaseSDNodeBits.AddressingMode = AM;
assert(getAddressingMode() == AM && "Value truncated");
}

// MaskedLoadSDNode (Chain, ptr, mask, passthru)
// MaskedStoreSDNode (Chain, data, ptr, mask)
// MaskedLoadSDNode (Chain, ptr, offset, mask, passthru)
// MaskedStoreSDNode (Chain, data, ptr, offset, mask)
// Mask is a vector of i1 elements
const SDValue &getBasePtr() const {
return getOperand(getOpcode() == ISD::MLOAD ? 1 : 2);
}
const SDValue &getMask() const {
const SDValue &getOffset() const {
return getOperand(getOpcode() == ISD::MLOAD ? 2 : 3);
}
const SDValue &getMask() const {
return getOperand(getOpcode() == ISD::MLOAD ? 3 : 4);
}

/// Return the addressing mode for this load or store:
/// unindexed, pre-inc, pre-dec, post-inc, or post-dec.
ISD::MemIndexedMode getAddressingMode() const {
return static_cast<ISD::MemIndexedMode>(LSBaseSDNodeBits.AddressingMode);
}

/// Return true if this is a pre/post inc/dec load/store.
bool isIndexed() const { return getAddressingMode() != ISD::UNINDEXED; }

/// Return true if this is NOT a pre/post inc/dec load/store.
bool isUnindexed() const { return getAddressingMode() == ISD::UNINDEXED; }

static bool classof(const SDNode *N) {
return N->getOpcode() == ISD::MLOAD ||
Expand All @@ -2299,9 +2320,9 @@ class MaskedLoadSDNode : public MaskedLoadStoreSDNode {
friend class SelectionDAG;

MaskedLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs,
ISD::LoadExtType ETy, bool IsExpanding, EVT MemVT,
MachineMemOperand *MMO)
: MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, VTs, MemVT, MMO) {
ISD::MemIndexedMode AM, ISD::LoadExtType ETy,
bool IsExpanding, EVT MemVT, MachineMemOperand *MMO)
: MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, VTs, AM, MemVT, MMO) {
LoadSDNodeBits.ExtTy = ETy;
LoadSDNodeBits.IsExpanding = IsExpanding;
}
Expand All @@ -2311,8 +2332,9 @@ class MaskedLoadSDNode : public MaskedLoadStoreSDNode {
}

const SDValue &getBasePtr() const { return getOperand(1); }
const SDValue &getMask() const { return getOperand(2); }
const SDValue &getPassThru() const { return getOperand(3); }
const SDValue &getOffset() const { return getOperand(2); }
const SDValue &getMask() const { return getOperand(3); }
const SDValue &getPassThru() const { return getOperand(4); }

static bool classof(const SDNode *N) {
return N->getOpcode() == ISD::MLOAD;
Expand All @@ -2327,9 +2349,9 @@ class MaskedStoreSDNode : public MaskedLoadStoreSDNode {
friend class SelectionDAG;

MaskedStoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs,
bool isTrunc, bool isCompressing, EVT MemVT,
MachineMemOperand *MMO)
: MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, VTs, MemVT, MMO) {
ISD::MemIndexedMode AM, bool isTrunc, bool isCompressing,
EVT MemVT, MachineMemOperand *MMO)
: MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, VTs, AM, MemVT, MMO) {
StoreSDNodeBits.IsTruncating = isTrunc;
StoreSDNodeBits.IsCompressing = isCompressing;
}
Expand All @@ -2345,9 +2367,10 @@ class MaskedStoreSDNode : public MaskedLoadStoreSDNode {
/// memory at base_addr.
bool isCompressingStore() const { return StoreSDNodeBits.IsCompressing; }

const SDValue &getValue() const { return getOperand(1); }
const SDValue &getValue() const { return getOperand(1); }
const SDValue &getBasePtr() const { return getOperand(2); }
const SDValue &getMask() const { return getOperand(3); }
const SDValue &getOffset() const { return getOperand(3); }
const SDValue &getMask() const { return getOperand(4); }

static bool classof(const SDNode *N) {
return N->getOpcode() == ISD::MSTORE;
Expand Down
114 changes: 85 additions & 29 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Expand Up @@ -1110,12 +1110,8 @@ class TargetLoweringBase {
/// Return how the indexed load should be treated: either it is legal, needs
/// to be promoted to a larger size, needs to be expanded to some other code
/// sequence, or the target has a custom expander for it.
LegalizeAction
getIndexedLoadAction(unsigned IdxMode, MVT VT) const {
assert(IdxMode < ISD::LAST_INDEXED_MODE && VT.isValid() &&
"Table isn't big enough!");
unsigned Ty = (unsigned)VT.SimpleTy;
return (LegalizeAction)((IndexedModeActions[Ty][IdxMode] & 0xf0) >> 4);
LegalizeAction getIndexedLoadAction(unsigned IdxMode, MVT VT) const {
return getIndexedModeAction(IdxMode, VT, IMAB_Load);
}

/// Return true if the specified indexed load is legal on this target.
Expand All @@ -1128,12 +1124,8 @@ class TargetLoweringBase {
/// Return how the indexed store should be treated: either it is legal, needs
/// to be promoted to a larger size, needs to be expanded to some other code
/// sequence, or the target has a custom expander for it.
LegalizeAction
getIndexedStoreAction(unsigned IdxMode, MVT VT) const {
assert(IdxMode < ISD::LAST_INDEXED_MODE && VT.isValid() &&
"Table isn't big enough!");
unsigned Ty = (unsigned)VT.SimpleTy;
return (LegalizeAction)(IndexedModeActions[Ty][IdxMode] & 0x0f);
LegalizeAction getIndexedStoreAction(unsigned IdxMode, MVT VT) const {
return getIndexedModeAction(IdxMode, VT, IMAB_Store);
}

/// Return true if the specified indexed load is legal on this target.
Expand All @@ -1143,6 +1135,34 @@ class TargetLoweringBase {
getIndexedStoreAction(IdxMode, VT.getSimpleVT()) == Custom);
}

/// Return how the indexed load should be treated: either it is legal, needs
/// to be promoted to a larger size, needs to be expanded to some other code
/// sequence, or the target has a custom expander for it.
LegalizeAction getIndexedMaskedLoadAction(unsigned IdxMode, MVT VT) const {
return getIndexedModeAction(IdxMode, VT, IMAB_MaskedLoad);
}

/// Return true if the specified indexed load is legal on this target.
bool isIndexedMaskedLoadLegal(unsigned IdxMode, EVT VT) const {
return VT.isSimple() &&
(getIndexedMaskedLoadAction(IdxMode, VT.getSimpleVT()) == Legal ||
getIndexedMaskedLoadAction(IdxMode, VT.getSimpleVT()) == Custom);
}

/// Return how the indexed store should be treated: either it is legal, needs
/// to be promoted to a larger size, needs to be expanded to some other code
/// sequence, or the target has a custom expander for it.
LegalizeAction getIndexedMaskedStoreAction(unsigned IdxMode, MVT VT) const {
return getIndexedModeAction(IdxMode, VT, IMAB_MaskedStore);
}

/// Return true if the specified indexed load is legal on this target.
bool isIndexedMaskedStoreLegal(unsigned IdxMode, EVT VT) const {
return VT.isSimple() &&
(getIndexedMaskedStoreAction(IdxMode, VT.getSimpleVT()) == Legal ||
getIndexedMaskedStoreAction(IdxMode, VT.getSimpleVT()) == Custom);
}

/// Return how the condition code should be treated: either it is legal, needs
/// to be expanded to some other code sequence, or the target has a custom
/// expander for it.
Expand Down Expand Up @@ -2030,27 +2050,37 @@ class TargetLoweringBase {
///
/// NOTE: All indexed mode loads are initialized to Expand in
/// TargetLowering.cpp
void setIndexedLoadAction(unsigned IdxMode, MVT VT,
LegalizeAction Action) {
assert(VT.isValid() && IdxMode < ISD::LAST_INDEXED_MODE &&
(unsigned)Action < 0xf && "Table isn't big enough!");
// Load action are kept in the upper half.
IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] &= ~0xf0;
IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] |= ((uint8_t)Action) <<4;
void setIndexedLoadAction(unsigned IdxMode, MVT VT, LegalizeAction Action) {
setIndexedModeAction(IdxMode, VT, IMAB_Load, Action);
}

/// Indicate that the specified indexed store does or does not work with the
/// specified type and indicate what to do about it.
///
/// NOTE: All indexed mode stores are initialized to Expand in
/// TargetLowering.cpp
void setIndexedStoreAction(unsigned IdxMode, MVT VT,
LegalizeAction Action) {
assert(VT.isValid() && IdxMode < ISD::LAST_INDEXED_MODE &&
(unsigned)Action < 0xf && "Table isn't big enough!");
// Store action are kept in the lower half.
IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] &= ~0x0f;
IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] |= ((uint8_t)Action);
void setIndexedStoreAction(unsigned IdxMode, MVT VT, LegalizeAction Action) {
setIndexedModeAction(IdxMode, VT, IMAB_Store, Action);
}

/// Indicate that the specified indexed masked load does or does not work with
/// the specified type and indicate what to do about it.
///
/// NOTE: All indexed mode masked loads are initialized to Expand in
/// TargetLowering.cpp
void setIndexedMaskedLoadAction(unsigned IdxMode, MVT VT,
LegalizeAction Action) {
setIndexedModeAction(IdxMode, VT, IMAB_MaskedLoad, Action);
}

/// Indicate that the specified indexed masked store does or does not work
/// with the specified type and indicate what to do about it.
///
/// NOTE: All indexed mode masked stores are initialized to Expand in
/// TargetLowering.cpp
void setIndexedMaskedStoreAction(unsigned IdxMode, MVT VT,
LegalizeAction Action) {
setIndexedModeAction(IdxMode, VT, IMAB_MaskedStore, Action);
}

/// Indicate that the specified condition code is or isn't supported on the
Expand Down Expand Up @@ -2763,13 +2793,13 @@ class TargetLoweringBase {
/// truncating store of a specific value type and truncating type is legal.
LegalizeAction TruncStoreActions[MVT::LAST_VALUETYPE][MVT::LAST_VALUETYPE];

/// For each indexed mode and each value type, keep a pair of LegalizeAction
/// For each indexed mode and each value type, keep a quad of LegalizeAction
/// that indicates how instruction selection should deal with the load /
/// store.
/// store / maskedload / maskedstore.
///
/// The first dimension is the value_type for the reference. The second
/// dimension represents the various modes for load store.
uint8_t IndexedModeActions[MVT::LAST_VALUETYPE][ISD::LAST_INDEXED_MODE];
uint16_t IndexedModeActions[MVT::LAST_VALUETYPE][ISD::LAST_INDEXED_MODE];

/// For each condition code (ISD::CondCode) keep a LegalizeAction that
/// indicates how instruction selection should deal with the condition code.
Expand Down Expand Up @@ -2812,6 +2842,32 @@ class TargetLoweringBase {
/// Set default libcall names and calling conventions.
void InitLibcalls(const Triple &TT);

/// The bits of IndexedModeActions used to store the legalisation actions
/// We store the data as | ML | MS | L | S | each taking 4 bits.
enum IndexedModeActionsBits {
IMAB_Store = 0,
IMAB_Load = 4,
IMAB_MaskedStore = 8,
IMAB_MaskedLoad = 12
};

void setIndexedModeAction(unsigned IdxMode, MVT VT, unsigned Shift,
LegalizeAction Action) {
assert(VT.isValid() && IdxMode < ISD::LAST_INDEXED_MODE &&
(unsigned)Action < 0xf && "Table isn't big enough!");
unsigned Ty = (unsigned)VT.SimpleTy;
IndexedModeActions[Ty][IdxMode] &= ~(0xf << Shift);
IndexedModeActions[Ty][IdxMode] |= ((uint16_t)Action) << Shift;
}

LegalizeAction getIndexedModeAction(unsigned IdxMode, MVT VT,
unsigned Shift) const {
assert(IdxMode < ISD::LAST_INDEXED_MODE && VT.isValid() &&
"Table isn't big enough!");
unsigned Ty = (unsigned)VT.SimpleTy;
return (LegalizeAction)((IndexedModeActions[Ty][IdxMode] >> Shift) & 0xf);
}

protected:
/// Return true if the extension represented by \p I is free.
/// \pre \p I is a sign, zero, or fp extension and
Expand Down
10 changes: 5 additions & 5 deletions llvm/include/llvm/Target/TargetSelectionDAG.td
Expand Up @@ -224,13 +224,13 @@ def SDTIStore : SDTypeProfile<1, 3, [ // indexed store
SDTCisSameAs<0, 2>, SDTCisPtrTy<0>, SDTCisPtrTy<3>
]>;

def SDTMaskedStore: SDTypeProfile<0, 3, [ // masked store
SDTCisVec<0>, SDTCisPtrTy<1>, SDTCisVec<2>, SDTCisSameNumEltsAs<0, 2>
def SDTMaskedStore: SDTypeProfile<0, 4, [ // masked store
SDTCisVec<0>, SDTCisPtrTy<1>, SDTCisPtrTy<2>, SDTCisVec<3>, SDTCisSameNumEltsAs<0, 3>
]>;

def SDTMaskedLoad: SDTypeProfile<1, 3, [ // masked load
SDTCisVec<0>, SDTCisPtrTy<1>, SDTCisVec<2>, SDTCisSameAs<0, 3>,
SDTCisSameNumEltsAs<0, 2>
def SDTMaskedLoad: SDTypeProfile<1, 4, [ // masked load
SDTCisVec<0>, SDTCisPtrTy<1>, SDTCisPtrTy<2>, SDTCisVec<3>, SDTCisSameAs<0, 4>,
SDTCisSameNumEltsAs<0, 3>
]>;

def SDTVecShuffle : SDTypeProfile<1, 2, [
Expand Down

0 comments on commit b5315ae

Please sign in to comment.