forked from OSchip/llvm-project
GlobalISel: Add alignment to LegalityQuery MMOs
This allows targets to specify the minimum alignment required for the load/store. llvm-svn: 354071
This commit is contained in:
parent
294483f1c0
commit
530d05e94a
|
@ -122,6 +122,7 @@ struct LegalityQuery {
|
||||||
|
|
||||||
struct MemDesc {
|
struct MemDesc {
|
||||||
uint64_t SizeInBits;
|
uint64_t SizeInBits;
|
||||||
|
uint64_t AlignInBits;
|
||||||
AtomicOrdering Ordering;
|
AtomicOrdering Ordering;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,13 +165,23 @@ using LegalizeMutation =
|
||||||
std::function<std::pair<unsigned, LLT>(const LegalityQuery &)>;
|
std::function<std::pair<unsigned, LLT>(const LegalityQuery &)>;
|
||||||
|
|
||||||
namespace LegalityPredicates {
|
namespace LegalityPredicates {
|
||||||
struct TypePairAndMemSize {
|
struct TypePairAndMemDesc {
|
||||||
LLT Type0;
|
LLT Type0;
|
||||||
LLT Type1;
|
LLT Type1;
|
||||||
uint64_t MemSize;
|
uint64_t MemSize;
|
||||||
|
uint64_t Align;
|
||||||
|
|
||||||
bool operator==(const TypePairAndMemSize &Other) const {
|
bool operator==(const TypePairAndMemDesc &Other) const {
|
||||||
return Type0 == Other.Type0 && Type1 == Other.Type1 &&
|
return Type0 == Other.Type0 && Type1 == Other.Type1 &&
|
||||||
|
Align == Other.Align &&
|
||||||
|
MemSize == Other.MemSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \returns true if this memory access is legal with for the acecss described
|
||||||
|
/// by \p Other (The alignment is sufficient for the size and result type).
|
||||||
|
bool isCompatible(const TypePairAndMemDesc &Other) const {
|
||||||
|
return Type0 == Other.Type0 && Type1 == Other.Type1 &&
|
||||||
|
Align >= Other.Align &&
|
||||||
MemSize == Other.MemSize;
|
MemSize == Other.MemSize;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -199,9 +210,9 @@ typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1,
|
||||||
std::initializer_list<std::pair<LLT, LLT>> TypesInit);
|
std::initializer_list<std::pair<LLT, LLT>> TypesInit);
|
||||||
/// True iff the given types for the given pair of type indexes is one of the
|
/// True iff the given types for the given pair of type indexes is one of the
|
||||||
/// specified type pairs.
|
/// specified type pairs.
|
||||||
LegalityPredicate typePairAndMemSizeInSet(
|
LegalityPredicate typePairAndMemDescInSet(
|
||||||
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
|
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
|
||||||
std::initializer_list<TypePairAndMemSize> TypesAndMemSizeInit);
|
std::initializer_list<TypePairAndMemDesc> TypesAndMemDescInit);
|
||||||
/// True iff the specified type index is a scalar.
|
/// True iff the specified type index is a scalar.
|
||||||
LegalityPredicate isScalar(unsigned TypeIdx);
|
LegalityPredicate isScalar(unsigned TypeIdx);
|
||||||
/// True iff the specified type index is a vector.
|
/// True iff the specified type index is a vector.
|
||||||
|
@ -455,13 +466,13 @@ public:
|
||||||
return actionFor(LegalizeAction::Legal, Types);
|
return actionFor(LegalizeAction::Legal, Types);
|
||||||
}
|
}
|
||||||
/// The instruction is legal when type indexes 0 and 1 along with the memory
|
/// The instruction is legal when type indexes 0 and 1 along with the memory
|
||||||
/// size is any type and size tuple in the given list.
|
/// size and minimum alignment is any type and size tuple in the given list.
|
||||||
LegalizeRuleSet &legalForTypesWithMemSize(
|
LegalizeRuleSet &legalForTypesWithMemDesc(
|
||||||
std::initializer_list<LegalityPredicates::TypePairAndMemSize>
|
std::initializer_list<LegalityPredicates::TypePairAndMemDesc>
|
||||||
TypesAndMemSize) {
|
TypesAndMemDesc) {
|
||||||
return actionIf(LegalizeAction::Legal,
|
return actionIf(LegalizeAction::Legal,
|
||||||
LegalityPredicates::typePairAndMemSizeInSet(
|
LegalityPredicates::typePairAndMemDescInSet(
|
||||||
typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemSize));
|
typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemDesc));
|
||||||
}
|
}
|
||||||
/// The instruction is legal when type indexes 0 and 1 are both in the given
|
/// The instruction is legal when type indexes 0 and 1 are both in the given
|
||||||
/// list. That is, the type pair is in the cartesian product of the list.
|
/// list. That is, the type pair is in the cartesian product of the list.
|
||||||
|
|
|
@ -38,15 +38,19 @@ LegalityPredicate LegalityPredicates::typePairInSet(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
LegalityPredicate LegalityPredicates::typePairAndMemSizeInSet(
|
LegalityPredicate LegalityPredicates::typePairAndMemDescInSet(
|
||||||
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
|
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
|
||||||
std::initializer_list<TypePairAndMemSize> TypesAndMemSizeInit) {
|
std::initializer_list<TypePairAndMemDesc> TypesAndMemDescInit) {
|
||||||
SmallVector<TypePairAndMemSize, 4> TypesAndMemSize = TypesAndMemSizeInit;
|
SmallVector<TypePairAndMemDesc, 4> TypesAndMemDesc = TypesAndMemDescInit;
|
||||||
return [=](const LegalityQuery &Query) {
|
return [=](const LegalityQuery &Query) {
|
||||||
TypePairAndMemSize Match = {Query.Types[TypeIdx0], Query.Types[TypeIdx1],
|
TypePairAndMemDesc Match = {Query.Types[TypeIdx0], Query.Types[TypeIdx1],
|
||||||
Query.MMODescrs[MMOIdx].SizeInBits};
|
Query.MMODescrs[MMOIdx].SizeInBits,
|
||||||
return std::find(TypesAndMemSize.begin(), TypesAndMemSize.end(), Match) !=
|
Query.MMODescrs[MMOIdx].AlignInBits};
|
||||||
TypesAndMemSize.end();
|
return std::find_if(
|
||||||
|
TypesAndMemDesc.begin(), TypesAndMemDesc.end(),
|
||||||
|
[=](const TypePairAndMemDesc &Entry) ->bool {
|
||||||
|
return Match.isCompatible(Entry);
|
||||||
|
}) != TypesAndMemDesc.end();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -423,8 +423,9 @@ LegalizerInfo::getAction(const MachineInstr &MI,
|
||||||
|
|
||||||
SmallVector<LegalityQuery::MemDesc, 2> MemDescrs;
|
SmallVector<LegalityQuery::MemDesc, 2> MemDescrs;
|
||||||
for (const auto &MMO : MI.memoperands())
|
for (const auto &MMO : MI.memoperands())
|
||||||
MemDescrs.push_back(
|
MemDescrs.push_back({8 * MMO->getSize() /* in bits */,
|
||||||
{MMO->getSize() /* in bytes */ * 8, MMO->getOrdering()});
|
8 * MMO->getAlignment(),
|
||||||
|
MMO->getOrdering()});
|
||||||
|
|
||||||
return getAction({MI.getOpcode(), Types, MemDescrs});
|
return getAction({MI.getOpcode(), Types, MemDescrs});
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,12 +192,12 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
|
||||||
.widenScalarToNextPow2(0);
|
.widenScalarToNextPow2(0);
|
||||||
|
|
||||||
getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
|
getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
|
||||||
.legalForTypesWithMemSize({{s32, p0, 8},
|
.legalForTypesWithMemDesc({{s32, p0, 8, 8},
|
||||||
{s32, p0, 16},
|
{s32, p0, 16, 8},
|
||||||
{s32, p0, 32},
|
{s32, p0, 32, 8},
|
||||||
{s64, p0, 64},
|
{s64, p0, 64, 8},
|
||||||
{p0, p0, 64},
|
{p0, p0, 64, 8},
|
||||||
{v2s32, p0, 64}})
|
{v2s32, p0, 64, 8}})
|
||||||
.clampScalar(0, s32, s64)
|
.clampScalar(0, s32, s64)
|
||||||
.widenScalarToNextPow2(0)
|
.widenScalarToNextPow2(0)
|
||||||
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
||||||
|
@ -207,15 +207,15 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
|
||||||
.lower();
|
.lower();
|
||||||
|
|
||||||
getActionDefinitionsBuilder(G_LOAD)
|
getActionDefinitionsBuilder(G_LOAD)
|
||||||
.legalForTypesWithMemSize({{s8, p0, 8},
|
.legalForTypesWithMemDesc({{s8, p0, 8, 8},
|
||||||
{s16, p0, 16},
|
{s16, p0, 16, 8},
|
||||||
{s32, p0, 32},
|
{s32, p0, 32, 8},
|
||||||
{s64, p0, 64},
|
{s64, p0, 64, 8},
|
||||||
{p0, p0, 64},
|
{p0, p0, 64, 8},
|
||||||
{v2s32, p0, 64}})
|
{v2s32, p0, 64, 8}})
|
||||||
// These extends are also legal
|
// These extends are also legal
|
||||||
.legalForTypesWithMemSize({{s32, p0, 8},
|
.legalForTypesWithMemDesc({{s32, p0, 8, 8},
|
||||||
{s32, p0, 16}})
|
{s32, p0, 16, 8}})
|
||||||
.clampScalar(0, s8, s64)
|
.clampScalar(0, s8, s64)
|
||||||
.widenScalarToNextPow2(0)
|
.widenScalarToNextPow2(0)
|
||||||
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
||||||
|
@ -229,12 +229,12 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
|
||||||
.clampMaxNumElements(0, s64, 1);
|
.clampMaxNumElements(0, s64, 1);
|
||||||
|
|
||||||
getActionDefinitionsBuilder(G_STORE)
|
getActionDefinitionsBuilder(G_STORE)
|
||||||
.legalForTypesWithMemSize({{s8, p0, 8},
|
.legalForTypesWithMemDesc({{s8, p0, 8, 8},
|
||||||
{s16, p0, 16},
|
{s16, p0, 16, 8},
|
||||||
{s32, p0, 32},
|
{s32, p0, 32, 8},
|
||||||
{s64, p0, 64},
|
{s64, p0, 64, 8},
|
||||||
{p0, p0, 64},
|
{p0, p0, 64, 8},
|
||||||
{v2s32, p0, 64}})
|
{v2s32, p0, 64, 8}})
|
||||||
.clampScalar(0, s8, s64)
|
.clampScalar(0, s8, s64)
|
||||||
.widenScalarToNextPow2(0)
|
.widenScalarToNextPow2(0)
|
||||||
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
||||||
|
|
|
@ -397,17 +397,18 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST,
|
||||||
.clampScalar(0, S32, S64);
|
.clampScalar(0, S32, S64);
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: Handle alignment requirements.
|
||||||
auto &ExtLoads = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
|
auto &ExtLoads = getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
|
||||||
.legalForTypesWithMemSize({
|
.legalForTypesWithMemDesc({
|
||||||
{S32, GlobalPtr, 8},
|
{S32, GlobalPtr, 8, 8},
|
||||||
{S32, GlobalPtr, 16},
|
{S32, GlobalPtr, 16, 8},
|
||||||
{S32, LocalPtr, 8},
|
{S32, LocalPtr, 8, 8},
|
||||||
{S32, LocalPtr, 16},
|
{S32, LocalPtr, 16, 8},
|
||||||
{S32, PrivatePtr, 8},
|
{S32, PrivatePtr, 8, 8},
|
||||||
{S32, PrivatePtr, 16}});
|
{S32, PrivatePtr, 16, 8}});
|
||||||
if (ST.hasFlatAddressSpace()) {
|
if (ST.hasFlatAddressSpace()) {
|
||||||
ExtLoads.legalForTypesWithMemSize({{S32, FlatPtr, 8},
|
ExtLoads.legalForTypesWithMemDesc({{S32, FlatPtr, 8, 8},
|
||||||
{S32, FlatPtr, 16}});
|
{S32, FlatPtr, 16, 8}});
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtLoads.clampScalar(0, S32, S32)
|
ExtLoads.clampScalar(0, S32, S32)
|
||||||
|
|
|
@ -131,12 +131,12 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
|
||||||
// floating point to them.
|
// floating point to them.
|
||||||
auto &LoadStoreBuilder =
|
auto &LoadStoreBuilder =
|
||||||
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
||||||
.legalForTypesWithMemSize({
|
.legalForTypesWithMemDesc({
|
||||||
{s1, p0, 8},
|
{s1, p0, 8, 8},
|
||||||
{s8, p0, 8},
|
{s8, p0, 8, 8},
|
||||||
{s16, p0, 16},
|
{s16, p0, 16, 8},
|
||||||
{s32, p0, 32},
|
{s32, p0, 32, 8},
|
||||||
{p0, p0, 32}});
|
{p0, p0, 32, 8}});
|
||||||
|
|
||||||
getActionDefinitionsBuilder(G_GEP).legalFor({{p0, s32}});
|
getActionDefinitionsBuilder(G_GEP).legalFor({{p0, s32}});
|
||||||
|
|
||||||
|
|
|
@ -36,15 +36,15 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
|
||||||
.lowerFor({{s32, s1}});
|
.lowerFor({{s32, s1}});
|
||||||
|
|
||||||
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
||||||
.legalForTypesWithMemSize({{s32, p0, 8},
|
.legalForTypesWithMemDesc({{s32, p0, 8, 8},
|
||||||
{s32, p0, 16},
|
{s32, p0, 16, 8},
|
||||||
{s32, p0, 32},
|
{s32, p0, 32, 8},
|
||||||
{p0, p0, 32}})
|
{p0, p0, 32, 8}})
|
||||||
.minScalar(0, s32);
|
.minScalar(0, s32);
|
||||||
|
|
||||||
getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
|
getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
|
||||||
.legalForTypesWithMemSize({{s32, p0, 8},
|
.legalForTypesWithMemDesc({{s32, p0, 8, 8},
|
||||||
{s32, p0, 16}})
|
{s32, p0, 16, 8}})
|
||||||
.minScalar(0, s32);
|
.minScalar(0, s32);
|
||||||
|
|
||||||
getActionDefinitionsBuilder(G_SELECT)
|
getActionDefinitionsBuilder(G_SELECT)
|
||||||
|
|
|
@ -356,3 +356,52 @@ TEST(LegalizerInfoTest, RuleSets) {
|
||||||
EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s33}));
|
EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s33}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(LegalizerInfoTest, MMOAlignment) {
|
||||||
|
using namespace TargetOpcode;
|
||||||
|
|
||||||
|
const LLT s32 = LLT::scalar(32);
|
||||||
|
const LLT p0 = LLT::pointer(0, 64);
|
||||||
|
|
||||||
|
{
|
||||||
|
LegalizerInfo LI;
|
||||||
|
LI.getActionDefinitionsBuilder(G_LOAD)
|
||||||
|
.legalForTypesWithMemDesc({{s32, p0, 32, 32}});
|
||||||
|
|
||||||
|
LI.computeTables();
|
||||||
|
|
||||||
|
EXPECT_ACTION(Legal, 0, LLT(),
|
||||||
|
LegalityQuery(G_LOAD, {s32, p0},
|
||||||
|
LegalityQuery::MemDesc{
|
||||||
|
32, 32, AtomicOrdering::NotAtomic}));
|
||||||
|
EXPECT_ACTION(Unsupported, 0, LLT(),
|
||||||
|
LegalityQuery(G_LOAD, {s32, p0},
|
||||||
|
LegalityQuery::MemDesc{
|
||||||
|
32, 16, AtomicOrdering::NotAtomic }));
|
||||||
|
EXPECT_ACTION(Unsupported, 0, LLT(),
|
||||||
|
LegalityQuery(G_LOAD, {s32, p0},
|
||||||
|
LegalityQuery::MemDesc{
|
||||||
|
32, 8, AtomicOrdering::NotAtomic}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the maximum supported alignment value isn't truncated
|
||||||
|
{
|
||||||
|
// Maximum IR defined alignment in bytes.
|
||||||
|
const uint64_t MaxAlignment = UINT64_C(1) << 29;
|
||||||
|
const uint64_t MaxAlignInBits = 8 * MaxAlignment;
|
||||||
|
LegalizerInfo LI;
|
||||||
|
LI.getActionDefinitionsBuilder(G_LOAD)
|
||||||
|
.legalForTypesWithMemDesc({{s32, p0, 32, MaxAlignInBits}});
|
||||||
|
|
||||||
|
LI.computeTables();
|
||||||
|
|
||||||
|
EXPECT_ACTION(Legal, 0, LLT(),
|
||||||
|
LegalityQuery(G_LOAD, {s32, p0},
|
||||||
|
LegalityQuery::MemDesc{32,
|
||||||
|
MaxAlignInBits, AtomicOrdering::NotAtomic}));
|
||||||
|
EXPECT_ACTION(Unsupported, 0, LLT(),
|
||||||
|
LegalityQuery(G_LOAD, {s32, p0},
|
||||||
|
LegalityQuery::MemDesc{
|
||||||
|
32, 8, AtomicOrdering::NotAtomic }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue