#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
#define LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/LowLevelTypeImpl.h"
#include <cassert>
#include <cstdint>
#include <tuple>
#include <utility>
namespace llvm {
extern cl::opt<bool> DisableGISelLegalityCheck;
class MachineFunction;
class raw_ostream;
class LegalizerHelper;
class MachineInstr;
class MachineRegisterInfo;
class MCInstrInfo;
namespace LegalizeActions {
enum LegalizeAction : std::uint8_t {
Legal,
NarrowScalar,
WidenScalar,
FewerElements,
MoreElements,
Bitcast,
Lower,
Libcall,
Custom,
Unsupported,
NotFound,
UseLegacyRules,
};
} raw_ostream &operator<<(raw_ostream &OS, LegalizeActions::LegalizeAction Action);
using LegalizeActions::LegalizeAction;
struct LegalityQuery {
unsigned Opcode;
ArrayRef<LLT> Types;
struct MemDesc {
LLT MemoryTy;
uint64_t AlignInBits;
AtomicOrdering Ordering;
MemDesc() = default;
MemDesc(LLT MemoryTy, uint64_t AlignInBits, AtomicOrdering Ordering)
: MemoryTy(MemoryTy), AlignInBits(AlignInBits), Ordering(Ordering) {}
MemDesc(const MachineMemOperand &MMO)
: MemoryTy(MMO.getMemoryType()),
AlignInBits(MMO.getAlign().value() * 8),
Ordering(MMO.getSuccessOrdering()) {}
};
ArrayRef<MemDesc> MMODescrs;
constexpr LegalityQuery(unsigned Opcode, const ArrayRef<LLT> Types,
const ArrayRef<MemDesc> MMODescrs)
: Opcode(Opcode), Types(Types), MMODescrs(MMODescrs) {}
constexpr LegalityQuery(unsigned Opcode, const ArrayRef<LLT> Types)
: LegalityQuery(Opcode, Types, {}) {}
raw_ostream &print(raw_ostream &OS) const;
};
struct LegalizeActionStep {
LegalizeAction Action;
unsigned TypeIdx;
LLT NewType;
LegalizeActionStep(LegalizeAction Action, unsigned TypeIdx,
const LLT NewType)
: Action(Action), TypeIdx(TypeIdx), NewType(NewType) {}
LegalizeActionStep(LegacyLegalizeActionStep Step)
: TypeIdx(Step.TypeIdx), NewType(Step.NewType) {
switch (Step.Action) {
case LegacyLegalizeActions::Legal:
Action = LegalizeActions::Legal;
break;
case LegacyLegalizeActions::NarrowScalar:
Action = LegalizeActions::NarrowScalar;
break;
case LegacyLegalizeActions::WidenScalar:
Action = LegalizeActions::WidenScalar;
break;
case LegacyLegalizeActions::FewerElements:
Action = LegalizeActions::FewerElements;
break;
case LegacyLegalizeActions::MoreElements:
Action = LegalizeActions::MoreElements;
break;
case LegacyLegalizeActions::Bitcast:
Action = LegalizeActions::Bitcast;
break;
case LegacyLegalizeActions::Lower:
Action = LegalizeActions::Lower;
break;
case LegacyLegalizeActions::Libcall:
Action = LegalizeActions::Libcall;
break;
case LegacyLegalizeActions::Custom:
Action = LegalizeActions::Custom;
break;
case LegacyLegalizeActions::Unsupported:
Action = LegalizeActions::Unsupported;
break;
case LegacyLegalizeActions::NotFound:
Action = LegalizeActions::NotFound;
break;
}
}
bool operator==(const LegalizeActionStep &RHS) const {
return std::tie(Action, TypeIdx, NewType) ==
std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType);
}
};
using LegalityPredicate = std::function<bool (const LegalityQuery &)>;
using LegalizeMutation =
std::function<std::pair<unsigned, LLT>(const LegalityQuery &)>;
namespace LegalityPredicates {
struct TypePairAndMemDesc {
LLT Type0;
LLT Type1;
LLT MemTy;
uint64_t Align;
bool operator==(const TypePairAndMemDesc &Other) const {
return Type0 == Other.Type0 && Type1 == Other.Type1 &&
Align == Other.Align && MemTy == Other.MemTy;
}
bool isCompatible(const TypePairAndMemDesc &Other) const {
return Type0 == Other.Type0 && Type1 == Other.Type1 &&
Align >= Other.Align &&
MemTy.getSizeInBits() == Other.MemTy.getSizeInBits();
}
};
template<typename Predicate>
Predicate all(Predicate P0, Predicate P1) {
return [=](const LegalityQuery &Query) {
return P0(Query) && P1(Query);
};
}
template<typename Predicate, typename... Args>
Predicate all(Predicate P0, Predicate P1, Args... args) {
return all(all(P0, P1), args...);
}
template<typename Predicate>
Predicate any(Predicate P0, Predicate P1) {
return [=](const LegalityQuery &Query) {
return P0(Query) || P1(Query);
};
}
template<typename Predicate, typename... Args>
Predicate any(Predicate P0, Predicate P1, Args... args) {
return any(any(P0, P1), args...);
}
LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit);
LegalityPredicate typeInSet(unsigned TypeIdx,
std::initializer_list<LLT> TypesInit);
inline LegalityPredicate typeIsNot(unsigned TypeIdx, LLT Type) {
return [=](const LegalityQuery &Query) {
return Query.Types[TypeIdx] != Type;
};
}
LegalityPredicate
typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1,
std::initializer_list<std::pair<LLT, LLT>> TypesInit);
LegalityPredicate typePairAndMemDescInSet(
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
std::initializer_list<TypePairAndMemDesc> TypesAndMemDescInit);
LegalityPredicate isScalar(unsigned TypeIdx);
LegalityPredicate isVector(unsigned TypeIdx);
LegalityPredicate isPointer(unsigned TypeIdx);
LegalityPredicate isPointer(unsigned TypeIdx, unsigned AddrSpace);
LegalityPredicate elementTypeIs(unsigned TypeIdx, LLT EltTy);
LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size);
LegalityPredicate scalarWiderThan(unsigned TypeIdx, unsigned Size);
LegalityPredicate scalarOrEltNarrowerThan(unsigned TypeIdx, unsigned Size);
LegalityPredicate scalarOrEltWiderThan(unsigned TypeIdx, unsigned Size);
LegalityPredicate sizeNotMultipleOf(unsigned TypeIdx, unsigned Size);
LegalityPredicate sizeNotPow2(unsigned TypeIdx);
LegalityPredicate scalarOrEltSizeNotPow2(unsigned TypeIdx);
LegalityPredicate sizeIs(unsigned TypeIdx, unsigned Size);
LegalityPredicate sameSize(unsigned TypeIdx0, unsigned TypeIdx1);
LegalityPredicate largerThan(unsigned TypeIdx0, unsigned TypeIdx1);
LegalityPredicate smallerThan(unsigned TypeIdx0, unsigned TypeIdx1);
LegalityPredicate memSizeInBytesNotPow2(unsigned MMOIdx);
LegalityPredicate memSizeNotByteSizePow2(unsigned MMOIdx);
LegalityPredicate numElementsNotPow2(unsigned TypeIdx);
LegalityPredicate atomicOrderingAtLeastOrStrongerThan(unsigned MMOIdx,
AtomicOrdering Ordering);
}
namespace LegalizeMutations {
LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty);
LegalizeMutation changeTo(unsigned TypeIdx, unsigned FromTypeIdx);
LegalizeMutation changeElementTo(unsigned TypeIdx, unsigned FromTypeIdx);
LegalizeMutation changeElementTo(unsigned TypeIdx, LLT Ty);
LegalizeMutation changeElementCountTo(unsigned TypeIdx, unsigned FromTypeIdx);
LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty);
LegalizeMutation changeElementSizeTo(unsigned TypeIdx, unsigned FromTypeIdx);
LegalizeMutation widenScalarOrEltToNextPow2(unsigned TypeIdx, unsigned Min = 0);
LegalizeMutation widenScalarOrEltToNextMultipleOf(unsigned TypeIdx,
unsigned Size);
LegalizeMutation moreElementsToNextPow2(unsigned TypeIdx, unsigned Min = 0);
LegalizeMutation scalarize(unsigned TypeIdx);
}
class LegalizeRule {
LegalityPredicate Predicate;
LegalizeAction Action;
LegalizeMutation Mutation;
public:
LegalizeRule(LegalityPredicate Predicate, LegalizeAction Action,
LegalizeMutation Mutation = nullptr)
: Predicate(Predicate), Action(Action), Mutation(Mutation) {}
bool match(const LegalityQuery &Query) const {
return Predicate(Query);
}
LegalizeAction getAction() const { return Action; }
std::pair<unsigned, LLT> determineMutation(const LegalityQuery &Query) const {
if (Mutation)
return Mutation(Query);
return std::make_pair(0, LLT{});
}
};
class LegalizeRuleSet {
unsigned AliasOf = 0;
bool IsAliasedByAnother = false;
SmallVector<LegalizeRule, 2> Rules;
#ifndef NDEBUG
SmallBitVector TypeIdxsCovered{MCOI::OPERAND_LAST_GENERIC -
MCOI::OPERAND_FIRST_GENERIC + 2};
SmallBitVector ImmIdxsCovered{MCOI::OPERAND_LAST_GENERIC_IMM -
MCOI::OPERAND_FIRST_GENERIC_IMM + 2};
#endif
unsigned typeIdx(unsigned TypeIdx) {
assert(TypeIdx <=
(MCOI::OPERAND_LAST_GENERIC - MCOI::OPERAND_FIRST_GENERIC) &&
"Type Index is out of bounds");
#ifndef NDEBUG
TypeIdxsCovered.set(TypeIdx);
#endif
return TypeIdx;
}
void markAllIdxsAsCovered() {
#ifndef NDEBUG
TypeIdxsCovered.set();
ImmIdxsCovered.set();
#endif
}
void add(const LegalizeRule &Rule) {
assert(AliasOf == 0 &&
"RuleSet is aliased, change the representative opcode instead");
Rules.push_back(Rule);
}
static bool always(const LegalityQuery &) { return true; }
LegalizeRuleSet &actionIf(LegalizeAction Action,
LegalityPredicate Predicate) {
add({Predicate, Action});
return *this;
}
LegalizeRuleSet &actionIf(LegalizeAction Action, LegalityPredicate Predicate,
LegalizeMutation Mutation) {
add({Predicate, Action, Mutation});
return *this;
}
LegalizeRuleSet &actionFor(LegalizeAction Action,
std::initializer_list<LLT> Types) {
using namespace LegalityPredicates;
return actionIf(Action, typeInSet(typeIdx(0), Types));
}
LegalizeRuleSet &actionFor(LegalizeAction Action,
std::initializer_list<LLT> Types,
LegalizeMutation Mutation) {
using namespace LegalityPredicates;
return actionIf(Action, typeInSet(typeIdx(0), Types), Mutation);
}
LegalizeRuleSet &actionFor(LegalizeAction Action,
std::initializer_list<std::pair<LLT, LLT>> Types) {
using namespace LegalityPredicates;
return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types));
}
LegalizeRuleSet &actionFor(LegalizeAction Action,
std::initializer_list<std::pair<LLT, LLT>> Types,
LegalizeMutation Mutation) {
using namespace LegalityPredicates;
return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types),
Mutation);
}
LegalizeRuleSet &actionForTypeWithAnyImm(LegalizeAction Action,
std::initializer_list<LLT> Types) {
using namespace LegalityPredicates;
immIdx(0); return actionIf(Action, typeInSet(typeIdx(0), Types));
}
LegalizeRuleSet &actionForTypeWithAnyImm(
LegalizeAction Action, std::initializer_list<std::pair<LLT, LLT>> Types) {
using namespace LegalityPredicates;
immIdx(0); return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types));
}
LegalizeRuleSet &actionForCartesianProduct(LegalizeAction Action,
std::initializer_list<LLT> Types) {
using namespace LegalityPredicates;
return actionIf(Action, all(typeInSet(typeIdx(0), Types),
typeInSet(typeIdx(1), Types)));
}
LegalizeRuleSet &
actionForCartesianProduct(LegalizeAction Action,
std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1) {
using namespace LegalityPredicates;
return actionIf(Action, all(typeInSet(typeIdx(0), Types0),
typeInSet(typeIdx(1), Types1)));
}
LegalizeRuleSet &actionForCartesianProduct(
LegalizeAction Action, std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1, std::initializer_list<LLT> Types2) {
using namespace LegalityPredicates;
return actionIf(Action, all(typeInSet(typeIdx(0), Types0),
all(typeInSet(typeIdx(1), Types1),
typeInSet(typeIdx(2), Types2))));
}
public:
LegalizeRuleSet() = default;
bool isAliasedByAnother() { return IsAliasedByAnother; }
void setIsAliasedByAnother() { IsAliasedByAnother = true; }
void aliasTo(unsigned Opcode) {
assert((AliasOf == 0 || AliasOf == Opcode) &&
"Opcode is already aliased to another opcode");
assert(Rules.empty() && "Aliasing will discard rules");
AliasOf = Opcode;
}
unsigned getAlias() const { return AliasOf; }
unsigned immIdx(unsigned ImmIdx) {
assert(ImmIdx <= (MCOI::OPERAND_LAST_GENERIC_IMM -
MCOI::OPERAND_FIRST_GENERIC_IMM) &&
"Imm Index is out of bounds");
#ifndef NDEBUG
ImmIdxsCovered.set(ImmIdx);
#endif
return ImmIdx;
}
LegalizeRuleSet &legalIf(LegalityPredicate Predicate) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Legal, Predicate);
}
LegalizeRuleSet &legalFor(std::initializer_list<LLT> Types) {
return actionFor(LegalizeAction::Legal, Types);
}
LegalizeRuleSet &legalFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
return actionFor(LegalizeAction::Legal, Types);
}
LegalizeRuleSet &legalForTypeWithAnyImm(std::initializer_list<LLT> Types) {
markAllIdxsAsCovered();
return actionForTypeWithAnyImm(LegalizeAction::Legal, Types);
}
LegalizeRuleSet &legalForTypeWithAnyImm(
std::initializer_list<std::pair<LLT, LLT>> Types) {
markAllIdxsAsCovered();
return actionForTypeWithAnyImm(LegalizeAction::Legal, Types);
}
LegalizeRuleSet &legalForTypesWithMemDesc(
std::initializer_list<LegalityPredicates::TypePairAndMemDesc>
TypesAndMemDesc) {
return actionIf(LegalizeAction::Legal,
LegalityPredicates::typePairAndMemDescInSet(
typeIdx(0), typeIdx(1), 0, TypesAndMemDesc));
}
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types) {
return actionForCartesianProduct(LegalizeAction::Legal, Types);
}
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1) {
return actionForCartesianProduct(LegalizeAction::Legal, Types0, Types1);
}
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1,
std::initializer_list<LLT> Types2) {
return actionForCartesianProduct(LegalizeAction::Legal, Types0, Types1,
Types2);
}
LegalizeRuleSet &alwaysLegal() {
using namespace LegalizeMutations;
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Legal, always);
}
LegalizeRuleSet &bitcastIf(LegalityPredicate Predicate,
LegalizeMutation Mutation) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Bitcast, Predicate, Mutation);
}
LegalizeRuleSet &lower() {
using namespace LegalizeMutations;
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Lower, always);
}
LegalizeRuleSet &lowerIf(LegalityPredicate Predicate) {
using namespace LegalizeMutations;
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Lower, Predicate);
}
LegalizeRuleSet &lowerIf(LegalityPredicate Predicate,
LegalizeMutation Mutation) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Lower, Predicate, Mutation);
}
LegalizeRuleSet &lowerFor(std::initializer_list<LLT> Types) {
return actionFor(LegalizeAction::Lower, Types);
}
LegalizeRuleSet &lowerFor(std::initializer_list<LLT> Types,
LegalizeMutation Mutation) {
return actionFor(LegalizeAction::Lower, Types, Mutation);
}
LegalizeRuleSet &lowerFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
return actionFor(LegalizeAction::Lower, Types);
}
LegalizeRuleSet &lowerFor(std::initializer_list<std::pair<LLT, LLT>> Types,
LegalizeMutation Mutation) {
return actionFor(LegalizeAction::Lower, Types, Mutation);
}
LegalizeRuleSet &lowerForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1) {
using namespace LegalityPredicates;
return actionForCartesianProduct(LegalizeAction::Lower, Types0, Types1);
}
LegalizeRuleSet &lowerForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1,
std::initializer_list<LLT> Types2) {
using namespace LegalityPredicates;
return actionForCartesianProduct(LegalizeAction::Lower, Types0, Types1,
Types2);
}
LegalizeRuleSet &libcall() {
using namespace LegalizeMutations;
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Libcall, always);
}
LegalizeRuleSet &libcallIf(LegalityPredicate Predicate) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Libcall, Predicate);
}
LegalizeRuleSet &libcallFor(std::initializer_list<LLT> Types) {
return actionFor(LegalizeAction::Libcall, Types);
}
LegalizeRuleSet &
libcallFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
return actionFor(LegalizeAction::Libcall, Types);
}
LegalizeRuleSet &
libcallForCartesianProduct(std::initializer_list<LLT> Types) {
return actionForCartesianProduct(LegalizeAction::Libcall, Types);
}
LegalizeRuleSet &
libcallForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1) {
return actionForCartesianProduct(LegalizeAction::Libcall, Types0, Types1);
}
LegalizeRuleSet &widenScalarIf(LegalityPredicate Predicate,
LegalizeMutation Mutation) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::WidenScalar, Predicate, Mutation);
}
LegalizeRuleSet &narrowScalarIf(LegalityPredicate Predicate,
LegalizeMutation Mutation) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::NarrowScalar, Predicate, Mutation);
}
LegalizeRuleSet &
narrowScalarFor(std::initializer_list<std::pair<LLT, LLT>> Types,
LegalizeMutation Mutation) {
return actionFor(LegalizeAction::NarrowScalar, Types, Mutation);
}
LegalizeRuleSet &moreElementsIf(LegalityPredicate Predicate,
LegalizeMutation Mutation) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::MoreElements, Predicate, Mutation);
}
LegalizeRuleSet &fewerElementsIf(LegalityPredicate Predicate,
LegalizeMutation Mutation) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::FewerElements, Predicate, Mutation);
}
LegalizeRuleSet &unsupported() {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Unsupported, always);
}
LegalizeRuleSet &unsupportedIf(LegalityPredicate Predicate) {
return actionIf(LegalizeAction::Unsupported, Predicate);
}
LegalizeRuleSet &unsupportedFor(std::initializer_list<LLT> Types) {
return actionFor(LegalizeAction::Unsupported, Types);
}
LegalizeRuleSet &unsupportedIfMemSizeNotPow2() {
return actionIf(LegalizeAction::Unsupported,
LegalityPredicates::memSizeInBytesNotPow2(0));
}
LegalizeRuleSet &lowerIfMemSizeNotPow2() {
return actionIf(LegalizeAction::Lower,
LegalityPredicates::memSizeInBytesNotPow2(0));
}
LegalizeRuleSet &lowerIfMemSizeNotByteSizePow2() {
return actionIf(LegalizeAction::Lower,
LegalityPredicates::memSizeNotByteSizePow2(0));
}
LegalizeRuleSet &customIf(LegalityPredicate Predicate) {
markAllIdxsAsCovered();
return actionIf(LegalizeAction::Custom, Predicate);
}
LegalizeRuleSet &customFor(std::initializer_list<LLT> Types) {
return actionFor(LegalizeAction::Custom, Types);
}
LegalizeRuleSet &customFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
return actionFor(LegalizeAction::Custom, Types);
}
LegalizeRuleSet &customForCartesianProduct(std::initializer_list<LLT> Types) {
return actionForCartesianProduct(LegalizeAction::Custom, Types);
}
LegalizeRuleSet &
customForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1) {
return actionForCartesianProduct(LegalizeAction::Custom, Types0, Types1);
}
LegalizeRuleSet &
customForCartesianProduct(std::initializer_list<LLT> Types0,
std::initializer_list<LLT> Types1,
std::initializer_list<LLT> Types2) {
return actionForCartesianProduct(LegalizeAction::Custom, Types0, Types1,
Types2);
}
LegalizeRuleSet &custom() {
return customIf(always);
}
LegalizeRuleSet &widenScalarToNextPow2(unsigned TypeIdx,
unsigned MinSize = 0) {
using namespace LegalityPredicates;
return actionIf(
LegalizeAction::WidenScalar, sizeNotPow2(typeIdx(TypeIdx)),
LegalizeMutations::widenScalarOrEltToNextPow2(TypeIdx, MinSize));
}
LegalizeRuleSet &widenScalarToNextMultipleOf(unsigned TypeIdx,
unsigned Size) {
using namespace LegalityPredicates;
return actionIf(
LegalizeAction::WidenScalar, sizeNotMultipleOf(typeIdx(TypeIdx), Size),
LegalizeMutations::widenScalarOrEltToNextMultipleOf(TypeIdx, Size));
}
LegalizeRuleSet &widenScalarOrEltToNextPow2(unsigned TypeIdx,
unsigned MinSize = 0) {
using namespace LegalityPredicates;
return actionIf(
LegalizeAction::WidenScalar, scalarOrEltSizeNotPow2(typeIdx(TypeIdx)),
LegalizeMutations::widenScalarOrEltToNextPow2(TypeIdx, MinSize));
}
LegalizeRuleSet &narrowScalar(unsigned TypeIdx, LegalizeMutation Mutation) {
using namespace LegalityPredicates;
return actionIf(LegalizeAction::NarrowScalar, isScalar(typeIdx(TypeIdx)),
Mutation);
}
LegalizeRuleSet &scalarize(unsigned TypeIdx) {
using namespace LegalityPredicates;
return actionIf(LegalizeAction::FewerElements, isVector(typeIdx(TypeIdx)),
LegalizeMutations::scalarize(TypeIdx));
}
LegalizeRuleSet &scalarizeIf(LegalityPredicate Predicate, unsigned TypeIdx) {
using namespace LegalityPredicates;
return actionIf(LegalizeAction::FewerElements,
all(Predicate, isVector(typeIdx(TypeIdx))),
LegalizeMutations::scalarize(TypeIdx));
}
LegalizeRuleSet &minScalarOrElt(unsigned TypeIdx, const LLT Ty) {
using namespace LegalityPredicates;
using namespace LegalizeMutations;
return actionIf(LegalizeAction::WidenScalar,
scalarOrEltNarrowerThan(TypeIdx, Ty.getScalarSizeInBits()),
changeElementTo(typeIdx(TypeIdx), Ty));
}
LegalizeRuleSet &minScalarOrEltIf(LegalityPredicate Predicate,
unsigned TypeIdx, const LLT Ty) {
using namespace LegalityPredicates;
using namespace LegalizeMutations;
return actionIf(LegalizeAction::WidenScalar,
all(Predicate, scalarOrEltNarrowerThan(
TypeIdx, Ty.getScalarSizeInBits())),
changeElementTo(typeIdx(TypeIdx), Ty));
}
LegalizeRuleSet &minScalar(unsigned TypeIdx, const LLT Ty) {
using namespace LegalityPredicates;
using namespace LegalizeMutations;
return actionIf(LegalizeAction::WidenScalar,
scalarNarrowerThan(TypeIdx, Ty.getSizeInBits()),
changeTo(typeIdx(TypeIdx), Ty));
}
LegalizeRuleSet &maxScalarOrElt(unsigned TypeIdx, const LLT Ty) {
using namespace LegalityPredicates;
using namespace LegalizeMutations;
return actionIf(LegalizeAction::NarrowScalar,
scalarOrEltWiderThan(TypeIdx, Ty.getScalarSizeInBits()),
changeElementTo(typeIdx(TypeIdx), Ty));
}
LegalizeRuleSet &maxScalar(unsigned TypeIdx, const LLT Ty) {
using namespace LegalityPredicates;
using namespace LegalizeMutations;
return actionIf(LegalizeAction::NarrowScalar,
scalarWiderThan(TypeIdx, Ty.getSizeInBits()),
changeTo(typeIdx(TypeIdx), Ty));
}
LegalizeRuleSet &maxScalarIf(LegalityPredicate Predicate, unsigned TypeIdx,
const LLT Ty) {
using namespace LegalityPredicates;
using namespace LegalizeMutations;
return actionIf(
LegalizeAction::NarrowScalar,
[=](const LegalityQuery &Query) {
const LLT QueryTy = Query.Types[TypeIdx];
return QueryTy.isScalar() &&
QueryTy.getSizeInBits() > Ty.getSizeInBits() &&
Predicate(Query);
},
changeElementTo(typeIdx(TypeIdx), Ty));
}
LegalizeRuleSet &clampScalar(unsigned TypeIdx, const LLT MinTy,
const LLT MaxTy) {
assert(MinTy.isScalar() && MaxTy.isScalar() && "Expected scalar types");
return minScalar(TypeIdx, MinTy).maxScalar(TypeIdx, MaxTy);
}
LegalizeRuleSet &clampScalarOrElt(unsigned TypeIdx, const LLT MinTy,
const LLT MaxTy) {
return minScalarOrElt(TypeIdx, MinTy).maxScalarOrElt(TypeIdx, MaxTy);
}
LegalizeRuleSet &minScalarSameAs(unsigned TypeIdx, unsigned LargeTypeIdx) {
typeIdx(TypeIdx);
return widenScalarIf(
[=](const LegalityQuery &Query) {
return Query.Types[LargeTypeIdx].getScalarSizeInBits() >
Query.Types[TypeIdx].getSizeInBits();
},
LegalizeMutations::changeElementSizeTo(TypeIdx, LargeTypeIdx));
}
LegalizeRuleSet &maxScalarSameAs(unsigned TypeIdx, unsigned NarrowTypeIdx) {
typeIdx(TypeIdx);
return narrowScalarIf(
[=](const LegalityQuery &Query) {
return Query.Types[NarrowTypeIdx].getScalarSizeInBits() <
Query.Types[TypeIdx].getSizeInBits();
},
LegalizeMutations::changeElementSizeTo(TypeIdx, NarrowTypeIdx));
}
LegalizeRuleSet &scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx) {
return minScalarSameAs(TypeIdx, SameSizeIdx)
.maxScalarSameAs(TypeIdx, SameSizeIdx);
}
LegalizeRuleSet &minScalarEltSameAsIf(LegalityPredicate Predicate,
unsigned TypeIdx, unsigned LargeTypeIdx) {
typeIdx(TypeIdx);
return widenScalarIf(
[=](const LegalityQuery &Query) {
return Query.Types[LargeTypeIdx].getScalarSizeInBits() >
Query.Types[TypeIdx].getScalarSizeInBits() &&
Predicate(Query);
},
[=](const LegalityQuery &Query) {
LLT T = Query.Types[LargeTypeIdx];
return std::make_pair(TypeIdx, T);
});
}
LegalizeRuleSet &maxScalarEltSameAsIf(LegalityPredicate Predicate,
unsigned TypeIdx,
unsigned SmallTypeIdx) {
typeIdx(TypeIdx);
return narrowScalarIf(
[=](const LegalityQuery &Query) {
return Query.Types[SmallTypeIdx].getScalarSizeInBits() <
Query.Types[TypeIdx].getScalarSizeInBits() &&
Predicate(Query);
},
[=](const LegalityQuery &Query) {
LLT T = Query.Types[SmallTypeIdx];
return std::make_pair(TypeIdx, T);
});
}
LegalizeRuleSet &moreElementsToNextPow2(unsigned TypeIdx) {
using namespace LegalityPredicates;
return actionIf(LegalizeAction::MoreElements,
numElementsNotPow2(typeIdx(TypeIdx)),
LegalizeMutations::moreElementsToNextPow2(TypeIdx));
}
LegalizeRuleSet &clampMinNumElements(unsigned TypeIdx, const LLT EltTy,
unsigned MinElements) {
typeIdx(TypeIdx);
return actionIf(
LegalizeAction::MoreElements,
[=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[TypeIdx];
return VecTy.isVector() && VecTy.getElementType() == EltTy &&
VecTy.getNumElements() < MinElements;
},
[=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[TypeIdx];
return std::make_pair(
TypeIdx, LLT::fixed_vector(MinElements, VecTy.getElementType()));
});
}
LegalizeRuleSet &alignNumElementsTo(unsigned TypeIdx, const LLT EltTy,
unsigned NumElts) {
typeIdx(TypeIdx);
return actionIf(
LegalizeAction::MoreElements,
[=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[TypeIdx];
return VecTy.isVector() && VecTy.getElementType() == EltTy &&
(VecTy.getNumElements() % NumElts != 0);
},
[=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[TypeIdx];
unsigned NewSize = alignTo(VecTy.getNumElements(), NumElts);
return std::make_pair(
TypeIdx, LLT::fixed_vector(NewSize, VecTy.getElementType()));
});
}
LegalizeRuleSet &clampMaxNumElements(unsigned TypeIdx, const LLT EltTy,
unsigned MaxElements) {
typeIdx(TypeIdx);
return actionIf(
LegalizeAction::FewerElements,
[=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[TypeIdx];
return VecTy.isVector() && VecTy.getElementType() == EltTy &&
VecTy.getNumElements() > MaxElements;
},
[=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[TypeIdx];
LLT NewTy = LLT::scalarOrVector(ElementCount::getFixed(MaxElements),
VecTy.getElementType());
return std::make_pair(TypeIdx, NewTy);
});
}
LegalizeRuleSet &clampNumElements(unsigned TypeIdx, const LLT MinTy,
const LLT MaxTy) {
assert(MinTy.getElementType() == MaxTy.getElementType() &&
"Expected element types to agree");
const LLT EltTy = MinTy.getElementType();
return clampMinNumElements(TypeIdx, EltTy, MinTy.getNumElements())
.clampMaxNumElements(TypeIdx, EltTy, MaxTy.getNumElements());
}
LegalizeRuleSet &clampMaxNumElementsStrict(unsigned TypeIdx, const LLT EltTy,
unsigned NumElts) {
return alignNumElementsTo(TypeIdx, EltTy, NumElts)
.clampMaxNumElements(TypeIdx, EltTy, NumElts);
}
LegalizeRuleSet &fallback() {
add({always, LegalizeAction::UseLegacyRules});
return *this;
}
bool verifyTypeIdxsCoverage(unsigned NumTypeIdxs) const;
bool verifyImmIdxsCoverage(unsigned NumImmIdxs) const;
LegalizeActionStep apply(const LegalityQuery &Query) const;
};
class LegalizerInfo {
public:
virtual ~LegalizerInfo() = default;
const LegacyLegalizerInfo &getLegacyLegalizerInfo() const {
return LegacyInfo;
}
LegacyLegalizerInfo &getLegacyLegalizerInfo() { return LegacyInfo; }
unsigned getOpcodeIdxForOpcode(unsigned Opcode) const;
unsigned getActionDefinitionsIdx(unsigned Opcode) const;
void verify(const MCInstrInfo &MII) const;
const LegalizeRuleSet &getActionDefinitions(unsigned Opcode) const;
LegalizeRuleSet &getActionDefinitionsBuilder(unsigned Opcode);
LegalizeRuleSet &
getActionDefinitionsBuilder(std::initializer_list<unsigned> Opcodes);
void aliasActionDefinitions(unsigned OpcodeTo, unsigned OpcodeFrom);
LegalizeActionStep getAction(const LegalityQuery &Query) const;
LegalizeActionStep getAction(const MachineInstr &MI,
const MachineRegisterInfo &MRI) const;
bool isLegal(const LegalityQuery &Query) const {
return getAction(Query).Action == LegalizeAction::Legal;
}
bool isLegalOrCustom(const LegalityQuery &Query) const {
auto Action = getAction(Query).Action;
return Action == LegalizeAction::Legal || Action == LegalizeAction::Custom;
}
bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const;
bool isLegalOrCustom(const MachineInstr &MI,
const MachineRegisterInfo &MRI) const;
virtual bool legalizeCustom(LegalizerHelper &Helper,
MachineInstr &MI) const {
llvm_unreachable("must implement this if custom action is used");
}
virtual bool legalizeIntrinsic(LegalizerHelper &Helper,
MachineInstr &MI) const {
return true;
}
virtual unsigned getExtOpcodeForWideningConstant(LLT SmallTy) const;
private:
static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
LegalizeRuleSet RulesForOpcode[LastOp - FirstOp + 1];
LegacyLegalizerInfo LegacyInfo;
};
#ifndef NDEBUG
const MachineInstr *machineFunctionIsIllegal(const MachineFunction &MF);
#endif
}
#endif