forked from OSchip/llvm-project
[globalisel][legalizerinfo] Follow up on post-commit review comments after r323681
* Document most API's * Delete a useless function call * Fix a discrepancy between the single and multi-opcode variants of getActionDefinitions(). The multi-opcode variant now requires that more than one opcode is requested. Previously it acted much like the single-opcode form but unnecessarily enforced the requirements of the multi-opcode form. llvm-svn: 325067
This commit is contained in:
parent
3ce76ad26f
commit
7fc87360e9
|
@ -144,25 +144,46 @@ using LegalizeMutation =
|
|||
std::function<std::pair<unsigned, LLT>(const LegalityQuery &)>;
|
||||
|
||||
namespace LegalityPredicates {
|
||||
/// True iff P0 and P1 are true.
|
||||
LegalityPredicate all(LegalityPredicate P0, LegalityPredicate P1);
|
||||
/// True iff the given type index is one of the specified types.
|
||||
LegalityPredicate typeInSet(unsigned TypeIdx,
|
||||
std::initializer_list<LLT> TypesInit);
|
||||
/// True iff the given types for the given pair of type indexes is one of the
|
||||
/// specified type pairs.
|
||||
LegalityPredicate
|
||||
typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1,
|
||||
std::initializer_list<std::pair<LLT, LLT>> TypesInit);
|
||||
/// True iff the specified type index is a scalar.
|
||||
LegalityPredicate isScalar(unsigned TypeIdx);
|
||||
/// True iff the specified type index is a scalar that's narrower than the given
|
||||
/// size.
|
||||
LegalityPredicate narrowerThan(unsigned TypeIdx, unsigned Size);
|
||||
/// True iff the specified type index is a scalar that's wider than the given
|
||||
/// size.
|
||||
LegalityPredicate widerThan(unsigned TypeIdx, unsigned Size);
|
||||
/// True iff the specified type index is a scalar whose size is not a power of
|
||||
/// 2.
|
||||
LegalityPredicate sizeNotPow2(unsigned TypeIdx);
|
||||
/// True iff the specified type index is a vector whose element count is not a
|
||||
/// power of 2.
|
||||
LegalityPredicate numElementsNotPow2(unsigned TypeIdx);
|
||||
} // end namespace LegalityPredicates
|
||||
|
||||
namespace LegalizeMutations {
|
||||
/// Select this specific type for the given type index.
|
||||
LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty);
|
||||
/// Widen the type for the given type index to the next power of 2.
|
||||
LegalizeMutation widenScalarToNextPow2(unsigned TypeIdx, unsigned Min = 0);
|
||||
/// Add more elements to the type for the given type index to the next power of
|
||||
/// 2.
|
||||
LegalizeMutation moreElementsToNextPow2(unsigned TypeIdx, unsigned Min = 0);
|
||||
} // end namespace LegalizeMutations
|
||||
|
||||
/// A single rule in a legalizer info ruleset.
|
||||
/// The specified action is chosen when the predicate is true. Where appropriate
|
||||
/// for the action (e.g. for WidenScalar) the new type is selected using the
|
||||
/// given mutator.
|
||||
class LegalizeRule {
|
||||
LegalityPredicate Predicate;
|
||||
LegalizeAction Action;
|
||||
|
@ -173,11 +194,14 @@ public:
|
|||
LegalizeMutation Mutation = nullptr)
|
||||
: Predicate(Predicate), Action(Action), Mutation(Mutation) {}
|
||||
|
||||
/// Test whether the LegalityQuery matches.
|
||||
bool match(const LegalityQuery &Query) const {
|
||||
return Predicate(Query);
|
||||
}
|
||||
|
||||
LegalizeAction getAction() const { return Action; }
|
||||
|
||||
/// Determine the change to make.
|
||||
std::pair<unsigned, LLT> determineMutation(const LegalityQuery &Query) const {
|
||||
if (Mutation)
|
||||
return Mutation(Query);
|
||||
|
@ -200,32 +224,48 @@ class LegalizeRuleSet {
|
|||
|
||||
static bool always(const LegalityQuery &) { return true; }
|
||||
|
||||
/// Use the given action when the predicate is true.
|
||||
/// Action should not be an action that requires mutation.
|
||||
LegalizeRuleSet &actionIf(LegalizeAction Action,
|
||||
LegalityPredicate Predicate) {
|
||||
add({Predicate, Action});
|
||||
return *this;
|
||||
}
|
||||
/// Use the given action when the predicate is true.
|
||||
/// Action should not be an action that requires mutation.
|
||||
LegalizeRuleSet &actionIf(LegalizeAction Action, LegalityPredicate Predicate,
|
||||
LegalizeMutation Mutation) {
|
||||
add({Predicate, Action, Mutation});
|
||||
return *this;
|
||||
}
|
||||
/// Use the given action when type index 0 is any type in the given list.
|
||||
/// Action should not be an action that requires mutation.
|
||||
LegalizeRuleSet &actionFor(LegalizeAction Action,
|
||||
std::initializer_list<LLT> Types) {
|
||||
using namespace LegalityPredicates;
|
||||
return actionIf(Action, typeInSet(0, Types));
|
||||
}
|
||||
/// Use the given action when type indexes 0 and 1 is any type pair in the
|
||||
/// given list.
|
||||
/// Action should not be an action that requires mutation.
|
||||
LegalizeRuleSet &
|
||||
actionFor(LegalizeAction Action,
|
||||
std::initializer_list<std::pair<LLT, LLT>> Types) {
|
||||
using namespace LegalityPredicates;
|
||||
return actionIf(Action, typePairInSet(0, 1, Types));
|
||||
}
|
||||
/// Use the given action 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.
|
||||
/// Action should not be an action that requires mutation.
|
||||
LegalizeRuleSet &actionForCartesianProduct(LegalizeAction Action,
|
||||
std::initializer_list<LLT> Types) {
|
||||
using namespace LegalityPredicates;
|
||||
return actionIf(Action, all(typeInSet(0, Types), typeInSet(1, Types)));
|
||||
}
|
||||
/// Use the given action when type indexes 0 and 1 are both their respective
|
||||
/// lists.
|
||||
/// That is, the type pair is in the cartesian product of the lists
|
||||
/// Action should not be an action that requires mutation.
|
||||
LegalizeRuleSet &
|
||||
actionForCartesianProduct(LegalizeAction Action,
|
||||
std::initializer_list<LLT> Types0,
|
||||
|
@ -247,24 +287,32 @@ public:
|
|||
}
|
||||
unsigned getAlias() const { return AliasOf; }
|
||||
|
||||
// Primitive rule definition functions
|
||||
/// The instruction is legal if predicate is true.
|
||||
LegalizeRuleSet &legalIf(LegalityPredicate Predicate) {
|
||||
return actionIf(LegalizeAction::Legal, Predicate);
|
||||
}
|
||||
/// The instruction is legal when type index 0 is any type in the given list.
|
||||
LegalizeRuleSet &legalFor(std::initializer_list<LLT> Types) {
|
||||
return actionFor(LegalizeAction::Legal, Types);
|
||||
}
|
||||
/// The instruction is legal when type indexes 0 and 1 is any type pair in the
|
||||
/// given list.
|
||||
LegalizeRuleSet &legalFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
|
||||
return actionFor(LegalizeAction::Legal, Types);
|
||||
}
|
||||
/// 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.
|
||||
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types) {
|
||||
return actionForCartesianProduct(LegalizeAction::Legal, Types);
|
||||
}
|
||||
/// The instruction is legal when type indexes 0 and 1 are both their
|
||||
/// respective lists.
|
||||
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types0,
|
||||
std::initializer_list<LLT> Types1) {
|
||||
return actionForCartesianProduct(LegalizeAction::Legal, Types0, Types1);
|
||||
}
|
||||
|
||||
/// Like legalIf, but for the Libcall action.
|
||||
LegalizeRuleSet &libcallIf(LegalityPredicate Predicate) {
|
||||
return actionIf(LegalizeAction::Libcall, Predicate);
|
||||
}
|
||||
|
@ -285,24 +333,33 @@ public:
|
|||
return actionForCartesianProduct(LegalizeAction::Libcall, Types0, Types1);
|
||||
}
|
||||
|
||||
/// Widen the scalar to the one selected by the mutation if the predicate is
|
||||
/// true.
|
||||
LegalizeRuleSet &widenScalarIf(LegalityPredicate Predicate,
|
||||
LegalizeMutation Mutation) {
|
||||
return actionIf(LegalizeAction::WidenScalar, Predicate, Mutation);
|
||||
}
|
||||
/// Narrow the scalar to the one selected by the mutation if the predicate is
|
||||
/// true.
|
||||
LegalizeRuleSet &narrowScalarIf(LegalityPredicate Predicate,
|
||||
LegalizeMutation Mutation) {
|
||||
return actionIf(LegalizeAction::NarrowScalar, Predicate, Mutation);
|
||||
}
|
||||
|
||||
/// Add more elements to reach the type selected by the mutation if the
|
||||
/// predicate is true.
|
||||
LegalizeRuleSet &moreElementsIf(LegalityPredicate Predicate,
|
||||
LegalizeMutation Mutation) {
|
||||
return actionIf(LegalizeAction::MoreElements, Predicate, Mutation);
|
||||
}
|
||||
/// Remove elements to reach the type selected by the mutation if the
|
||||
/// predicate is true.
|
||||
LegalizeRuleSet &fewerElementsIf(LegalityPredicate Predicate,
|
||||
LegalizeMutation Mutation) {
|
||||
return actionIf(LegalizeAction::FewerElements, Predicate, Mutation);
|
||||
}
|
||||
|
||||
/// The instruction is unsupported.
|
||||
LegalizeRuleSet &unsupported() {
|
||||
return actionIf(LegalizeAction::Unsupported, always);
|
||||
}
|
||||
|
@ -325,7 +382,8 @@ public:
|
|||
return actionForCartesianProduct(LegalizeAction::Custom, Types0, Types1);
|
||||
}
|
||||
|
||||
// Convenience rule definition functions
|
||||
/// Widen the scalar to the next power of two that is at least MinSize.
|
||||
/// No effect if the type is not a scalar or is a power of two.
|
||||
LegalizeRuleSet &widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize = 0) {
|
||||
using namespace LegalityPredicates;
|
||||
return widenScalarIf(
|
||||
|
@ -338,6 +396,7 @@ public:
|
|||
return narrowScalarIf(isScalar(TypeIdx), Mutation);
|
||||
}
|
||||
|
||||
/// Ensure the scalar is at least as wide as Ty.
|
||||
LegalizeRuleSet &minScalar(unsigned TypeIdx, const LLT &Ty) {
|
||||
using namespace LegalityPredicates;
|
||||
using namespace LegalizeMutations;
|
||||
|
@ -345,6 +404,7 @@ public:
|
|||
changeTo(TypeIdx, Ty));
|
||||
}
|
||||
|
||||
/// Ensure the scalar is at most as wide as Ty.
|
||||
LegalizeRuleSet &maxScalar(unsigned TypeIdx, const LLT &Ty) {
|
||||
using namespace LegalityPredicates;
|
||||
using namespace LegalizeMutations;
|
||||
|
@ -352,6 +412,9 @@ public:
|
|||
changeTo(TypeIdx, Ty));
|
||||
}
|
||||
|
||||
/// Conditionally limit the maximum size of the scalar.
|
||||
/// For example, when the maximum size of one type depends on the size of
|
||||
/// another such as extracting N bits from an M bit container.
|
||||
LegalizeRuleSet &maxScalarIf(LegalityPredicate Predicate, unsigned TypeIdx, const LLT &Ty) {
|
||||
using namespace LegalityPredicates;
|
||||
using namespace LegalizeMutations;
|
||||
|
@ -363,6 +426,7 @@ public:
|
|||
changeTo(TypeIdx, Ty));
|
||||
}
|
||||
|
||||
/// Limit the range of scalar sizes to MinTy and MaxTy.
|
||||
LegalizeRuleSet &clampScalar(unsigned TypeIdx, const LLT &MinTy, const LLT &MaxTy) {
|
||||
assert(MinTy.isScalar() && MaxTy.isScalar() && "Expected scalar types");
|
||||
|
||||
|
@ -370,12 +434,16 @@ public:
|
|||
.maxScalar(TypeIdx, MaxTy);
|
||||
}
|
||||
|
||||
/// Add more elements to the vector to reach the next power of two.
|
||||
/// No effect if the type is not a vector or the element count is a power of
|
||||
/// two.
|
||||
LegalizeRuleSet &moreElementsToNextPow2(unsigned TypeIdx) {
|
||||
using namespace LegalityPredicates;
|
||||
return moreElementsIf(numElementsNotPow2(TypeIdx),
|
||||
LegalizeMutations::moreElementsToNextPow2(TypeIdx));
|
||||
}
|
||||
|
||||
/// Limit the number of elements in EltTy vectors to at least MinElements.
|
||||
LegalizeRuleSet &clampMinNumElements(unsigned TypeIdx, const LLT &EltTy,
|
||||
unsigned MinElements) {
|
||||
return moreElementsIf(
|
||||
|
@ -390,6 +458,7 @@ public:
|
|||
TypeIdx, LLT::vector(MinElements, VecTy.getScalarSizeInBits()));
|
||||
});
|
||||
}
|
||||
/// Limit the number of elements in EltTy vectors to at most MaxElements.
|
||||
LegalizeRuleSet &clampMaxNumElements(unsigned TypeIdx, const LLT &EltTy,
|
||||
unsigned MaxElements) {
|
||||
return fewerElementsIf(
|
||||
|
@ -404,6 +473,12 @@ public:
|
|||
TypeIdx, LLT::vector(MaxElements, VecTy.getScalarSizeInBits()));
|
||||
});
|
||||
}
|
||||
/// Limit the number of elements for the given vectors to at least MinTy's
|
||||
/// number of elements and at most MaxTy's number of elements.
|
||||
///
|
||||
/// No effect if the type is not a vector or does not have the same element
|
||||
/// type as the constraints.
|
||||
/// The element type of MinTy and MaxTy must match.
|
||||
LegalizeRuleSet &clampNumElements(unsigned TypeIdx, const LLT &MinTy,
|
||||
const LLT &MaxTy) {
|
||||
assert(MinTy.getElementType() == MaxTy.getElementType() &&
|
||||
|
@ -414,11 +489,14 @@ public:
|
|||
.clampMaxNumElements(TypeIdx, EltTy, MaxTy.getNumElements());
|
||||
}
|
||||
|
||||
/// Fallback on the previous implementation. This should only be used while
|
||||
/// porting a rule.
|
||||
LegalizeRuleSet &fallback() {
|
||||
add({always, LegalizeAction::UseLegacyRules});
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Apply the ruleset to the given LegalityQuery.
|
||||
LegalizeActionStep apply(const LegalityQuery &Query) const;
|
||||
};
|
||||
|
||||
|
@ -593,8 +671,30 @@ public:
|
|||
LegalizeAction DecreaseAction,
|
||||
LegalizeAction IncreaseAction);
|
||||
|
||||
/// Get the action definitions for the given opcode. Use this to run a
|
||||
/// LegalityQuery through the definitions.
|
||||
const LegalizeRuleSet &getActionDefinitions(unsigned Opcode) const;
|
||||
|
||||
/// Get the action definition builder for the given opcode. Use this to define
|
||||
/// the action definitions.
|
||||
///
|
||||
/// It is an error to request an opcode that has already been requested by the
|
||||
/// multiple-opcode variant.
|
||||
LegalizeRuleSet &getActionDefinitionsBuilder(unsigned Opcode);
|
||||
|
||||
/// Get the action definition builder for the given set of opcodes. Use this
|
||||
/// to define the action definitions for multiple opcodes at once. The first
|
||||
/// opcode given will be considered the representative opcode and will hold
|
||||
/// the definitions whereas the other opcodes will be configured to refer to
|
||||
/// the representative opcode. This lowers memory requirements and very
|
||||
/// slightly improves performance.
|
||||
///
|
||||
/// It would be very easy to introduce unexpected side-effects as a result of
|
||||
/// this aliasing if it were permitted to request different but intersecting
|
||||
/// sets of opcodes but that is difficult to keep track of. It is therefore an
|
||||
/// error to request the same opcode twice using this API, to request an
|
||||
/// opcode that already has definitions, or to use the single-opcode API on an
|
||||
/// opcode that has already been requested by this API.
|
||||
LegalizeRuleSet &
|
||||
getActionDefinitionsBuilder(std::initializer_list<unsigned> Opcodes);
|
||||
void aliasActionDefinitions(unsigned OpcodeTo, unsigned OpcodeFrom);
|
||||
|
|
|
@ -261,6 +261,10 @@ LegalizeRuleSet &LegalizerInfo::getActionDefinitionsBuilder(
|
|||
std::initializer_list<unsigned> Opcodes) {
|
||||
unsigned Representative = *Opcodes.begin();
|
||||
|
||||
assert(Opcodes.begin() != Opcodes.end() &&
|
||||
Opcodes.begin() + 1 != Opcodes.end() &&
|
||||
"Initializer list must have at least two opcodes");
|
||||
|
||||
for (auto I = Opcodes.begin() + 1, E = Opcodes.end(); I != E; ++I)
|
||||
aliasActionDefinitions(Representative, *I);
|
||||
|
||||
|
|
|
@ -240,7 +240,6 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
|
|||
getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG)
|
||||
.legalForCartesianProduct({s8, s16, s32, s64}, {p0});
|
||||
}
|
||||
getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG);
|
||||
|
||||
if (ST.hasLSE()) {
|
||||
for (auto Ty : {s8, s16, s32, s64}) {
|
||||
|
|
Loading…
Reference in New Issue