123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h ------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- /// \file
- /// Interface for Targets to specify which operations they can successfully
- /// select and how the others should be expanded most efficiently.
- /// This implementation has been deprecated for a long time but it still in use
- /// in a few places.
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
- #define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/CodeGen/TargetOpcodes.h"
- #include "llvm/Support/LowLevelTypeImpl.h"
- #include <unordered_map>
- namespace llvm {
- struct LegalityQuery;
- namespace LegacyLegalizeActions {
- enum LegacyLegalizeAction : std::uint8_t {
- /// The operation is expected to be selectable directly by the target, and
- /// no transformation is necessary.
- Legal,
- /// The operation should be synthesized from multiple instructions acting on
- /// a narrower scalar base-type. For example a 64-bit add might be
- /// implemented in terms of 32-bit add-with-carry.
- NarrowScalar,
- /// The operation should be implemented in terms of a wider scalar
- /// base-type. For example a <2 x s8> add could be implemented as a <2
- /// x s32> add (ignoring the high bits).
- WidenScalar,
- /// The (vector) operation should be implemented by splitting it into
- /// sub-vectors where the operation is legal. For example a <8 x s64> add
- /// might be implemented as 4 separate <2 x s64> adds.
- FewerElements,
- /// The (vector) operation should be implemented by widening the input
- /// vector and ignoring the lanes added by doing so. For example <2 x i8> is
- /// rarely legal, but you might perform an <8 x i8> and then only look at
- /// the first two results.
- MoreElements,
- /// Perform the operation on a different, but equivalently sized type.
- Bitcast,
- /// The operation itself must be expressed in terms of simpler actions on
- /// this target. E.g. a SREM replaced by an SDIV and subtraction.
- Lower,
- /// The operation should be implemented as a call to some kind of runtime
- /// support library. For example this usually happens on machines that don't
- /// support floating-point operations natively.
- Libcall,
- /// The target wants to do something special with this combination of
- /// operand and type. A callback will be issued when it is needed.
- Custom,
- /// This operation is completely unsupported on the target. A programming
- /// error has occurred.
- Unsupported,
- /// Sentinel value for when no action was found in the specified table.
- NotFound,
- };
- } // end namespace LegacyLegalizeActions
- raw_ostream &operator<<(raw_ostream &OS,
- LegacyLegalizeActions::LegacyLegalizeAction Action);
- /// Legalization is decided based on an instruction's opcode, which type slot
- /// we're considering, and what the existing type is. These aspects are gathered
- /// together for convenience in the InstrAspect class.
- struct InstrAspect {
- unsigned Opcode;
- unsigned Idx = 0;
- LLT Type;
- InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {}
- InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)
- : Opcode(Opcode), Idx(Idx), Type(Type) {}
- bool operator==(const InstrAspect &RHS) const {
- return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type;
- }
- };
- /// The result of a query. It either indicates a final answer of Legal or
- /// Unsupported or describes an action that must be taken to make an operation
- /// more legal.
- struct LegacyLegalizeActionStep {
- /// The action to take or the final answer.
- LegacyLegalizeActions::LegacyLegalizeAction Action;
- /// If describing an action, the type index to change. Otherwise zero.
- unsigned TypeIdx;
- /// If describing an action, the new type for TypeIdx. Otherwise LLT{}.
- LLT NewType;
- LegacyLegalizeActionStep(LegacyLegalizeActions::LegacyLegalizeAction Action,
- unsigned TypeIdx, const LLT NewType)
- : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {}
- bool operator==(const LegacyLegalizeActionStep &RHS) const {
- return std::tie(Action, TypeIdx, NewType) ==
- std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType);
- }
- };
- class LegacyLegalizerInfo {
- public:
- using SizeAndAction =
- std::pair<uint16_t, LegacyLegalizeActions::LegacyLegalizeAction>;
- using SizeAndActionsVec = std::vector<SizeAndAction>;
- using SizeChangeStrategy =
- std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>;
- LegacyLegalizerInfo();
- static bool needsLegalizingToDifferentSize(
- const LegacyLegalizeActions::LegacyLegalizeAction Action) {
- using namespace LegacyLegalizeActions;
- switch (Action) {
- case NarrowScalar:
- case WidenScalar:
- case FewerElements:
- case MoreElements:
- case Unsupported:
- return true;
- default:
- return false;
- }
- }
- /// Compute any ancillary tables needed to quickly decide how an operation
- /// should be handled. This must be called after all "set*Action"methods but
- /// before any query is made or incorrect results may be returned.
- void computeTables();
- /// More friendly way to set an action for common types that have an LLT
- /// representation.
- /// The LegacyLegalizeAction must be one for which
- /// NeedsLegalizingToDifferentSize returns false.
- void setAction(const InstrAspect &Aspect,
- LegacyLegalizeActions::LegacyLegalizeAction Action) {
- assert(!needsLegalizingToDifferentSize(Action));
- TablesInitialized = false;
- const unsigned OpcodeIdx = Aspect.Opcode - FirstOp;
- if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx)
- SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1);
- SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action;
- }
- /// The setAction calls record the non-size-changing legalization actions
- /// to take on specificly-sized types. The SizeChangeStrategy defines what
- /// to do when the size of the type needs to be changed to reach a legally
- /// sized type (i.e., one that was defined through a setAction call).
- /// e.g.
- /// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal);
- /// setLegalizeScalarToDifferentSizeStrategy(
- /// G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
- /// will end up defining getAction({G_ADD, 0, T}) to return the following
- /// actions for different scalar types T:
- /// LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)}
- /// LLT::scalar(32): {Legal, 0, LLT::scalar(32)}
- /// LLT::scalar(33)..: {NarrowScalar, 0, LLT::scalar(32)}
- ///
- /// If no SizeChangeAction gets defined, through this function,
- /// the default is unsupportedForDifferentSizes.
- void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode,
- const unsigned TypeIdx,
- SizeChangeStrategy S) {
- const unsigned OpcodeIdx = Opcode - FirstOp;
- if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
- ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
- ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
- }
- /// See also setLegalizeScalarToDifferentSizeStrategy.
- /// This function allows to set the SizeChangeStrategy for vector elements.
- void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode,
- const unsigned TypeIdx,
- SizeChangeStrategy S) {
- const unsigned OpcodeIdx = Opcode - FirstOp;
- if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
- VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
- VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
- }
- /// A SizeChangeStrategy for the common case where legalization for a
- /// particular operation consists of only supporting a specific set of type
- /// sizes. E.g.
- /// setAction ({G_DIV, 0, LLT::scalar(32)}, Legal);
- /// setAction ({G_DIV, 0, LLT::scalar(64)}, Legal);
- /// setLegalizeScalarToDifferentSizeStrategy(
- /// G_DIV, 0, unsupportedForDifferentSizes);
- /// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64,
- /// and Unsupported for all other scalar types T.
- static SizeAndActionsVec
- unsupportedForDifferentSizes(const SizeAndActionsVec &v) {
- using namespace LegacyLegalizeActions;
- return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported,
- Unsupported);
- }
- /// A SizeChangeStrategy for the common case where legalization for a
- /// particular operation consists of widening the type to a large legal type,
- /// unless there is no such type and then instead it should be narrowed to the
- /// largest legal type.
- static SizeAndActionsVec
- widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) {
- using namespace LegacyLegalizeActions;
- assert(v.size() > 0 &&
- "At least one size that can be legalized towards is needed"
- " for this SizeChangeStrategy");
- return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
- NarrowScalar);
- }
- static SizeAndActionsVec
- widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) {
- using namespace LegacyLegalizeActions;
- return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
- Unsupported);
- }
- static SizeAndActionsVec
- narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) {
- using namespace LegacyLegalizeActions;
- return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
- Unsupported);
- }
- static SizeAndActionsVec
- narrowToSmallerAndWidenToSmallest(const SizeAndActionsVec &v) {
- using namespace LegacyLegalizeActions;
- assert(v.size() > 0 &&
- "At least one size that can be legalized towards is needed"
- " for this SizeChangeStrategy");
- return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
- WidenScalar);
- }
- /// A SizeChangeStrategy for the common case where legalization for a
- /// particular vector operation consists of having more elements in the
- /// vector, to a type that is legal. Unless there is no such type and then
- /// instead it should be legalized towards the widest vector that's still
- /// legal. E.g.
- /// setAction({G_ADD, LLT::vector(8, 8)}, Legal);
- /// setAction({G_ADD, LLT::vector(16, 8)}, Legal);
- /// setAction({G_ADD, LLT::vector(2, 32)}, Legal);
- /// setAction({G_ADD, LLT::vector(4, 32)}, Legal);
- /// setLegalizeVectorElementToDifferentSizeStrategy(
- /// G_ADD, 0, moreToWiderTypesAndLessToWidest);
- /// will result in the following getAction results:
- /// * getAction({G_ADD, LLT::vector(8,8)}) returns
- /// (Legal, vector(8,8)).
- /// * getAction({G_ADD, LLT::vector(9,8)}) returns
- /// (MoreElements, vector(16,8)).
- /// * getAction({G_ADD, LLT::vector(8,32)}) returns
- /// (FewerElements, vector(4,32)).
- static SizeAndActionsVec
- moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) {
- using namespace LegacyLegalizeActions;
- return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements,
- FewerElements);
- }
- /// Helper function to implement many typical SizeChangeStrategy functions.
- static SizeAndActionsVec increaseToLargerTypesAndDecreaseToLargest(
- const SizeAndActionsVec &v,
- LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction,
- LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction);
- /// Helper function to implement many typical SizeChangeStrategy functions.
- static SizeAndActionsVec decreaseToSmallerTypesAndIncreaseToSmallest(
- const SizeAndActionsVec &v,
- LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction,
- LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction);
- LegacyLegalizeActionStep getAction(const LegalityQuery &Query) const;
- unsigned getOpcodeIdxForOpcode(unsigned Opcode) const;
- private:
- /// Determine what action should be taken to legalize the given generic
- /// instruction opcode, type-index and type. Requires computeTables to have
- /// been called.
- ///
- /// \returns a pair consisting of the kind of legalization that should be
- /// performed and the destination type.
- std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
- getAspectAction(const InstrAspect &Aspect) const;
- /// The SizeAndActionsVec is a representation mapping between all natural
- /// numbers and an Action. The natural number represents the bit size of
- /// the InstrAspect. For example, for a target with native support for 32-bit
- /// and 64-bit additions, you'd express that as:
- /// setScalarAction(G_ADD, 0,
- /// {{1, WidenScalar}, // bit sizes [ 1, 31[
- /// {32, Legal}, // bit sizes [32, 33[
- /// {33, WidenScalar}, // bit sizes [33, 64[
- /// {64, Legal}, // bit sizes [64, 65[
- /// {65, NarrowScalar} // bit sizes [65, +inf[
- /// });
- /// It may be that only 64-bit pointers are supported on your target:
- /// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1),
- /// {{1, Unsupported}, // bit sizes [ 1, 63[
- /// {64, Legal}, // bit sizes [64, 65[
- /// {65, Unsupported}, // bit sizes [65, +inf[
- /// });
- void setScalarAction(const unsigned Opcode, const unsigned TypeIndex,
- const SizeAndActionsVec &SizeAndActions) {
- const unsigned OpcodeIdx = Opcode - FirstOp;
- SmallVector<SizeAndActionsVec, 1> &Actions = ScalarActions[OpcodeIdx];
- setActions(TypeIndex, Actions, SizeAndActions);
- }
- void setPointerAction(const unsigned Opcode, const unsigned TypeIndex,
- const unsigned AddressSpace,
- const SizeAndActionsVec &SizeAndActions) {
- const unsigned OpcodeIdx = Opcode - FirstOp;
- if (AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace) ==
- AddrSpace2PointerActions[OpcodeIdx].end())
- AddrSpace2PointerActions[OpcodeIdx][AddressSpace] = {{}};
- SmallVector<SizeAndActionsVec, 1> &Actions =
- AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second;
- setActions(TypeIndex, Actions, SizeAndActions);
- }
- /// If an operation on a given vector type (say <M x iN>) isn't explicitly
- /// specified, we proceed in 2 stages. First we legalize the underlying scalar
- /// (so that there's at least one legal vector with that scalar), then we
- /// adjust the number of elements in the vector so that it is legal. The
- /// desired action in the first step is controlled by this function.
- void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex,
- const SizeAndActionsVec &SizeAndActions) {
- unsigned OpcodeIdx = Opcode - FirstOp;
- SmallVector<SizeAndActionsVec, 1> &Actions =
- ScalarInVectorActions[OpcodeIdx];
- setActions(TypeIndex, Actions, SizeAndActions);
- }
- /// See also setScalarInVectorAction.
- /// This function let's you specify the number of elements in a vector that
- /// are legal for a legal element size.
- void setVectorNumElementAction(const unsigned Opcode,
- const unsigned TypeIndex,
- const unsigned ElementSize,
- const SizeAndActionsVec &SizeAndActions) {
- const unsigned OpcodeIdx = Opcode - FirstOp;
- if (NumElements2Actions[OpcodeIdx].find(ElementSize) ==
- NumElements2Actions[OpcodeIdx].end())
- NumElements2Actions[OpcodeIdx][ElementSize] = {{}};
- SmallVector<SizeAndActionsVec, 1> &Actions =
- NumElements2Actions[OpcodeIdx].find(ElementSize)->second;
- setActions(TypeIndex, Actions, SizeAndActions);
- }
- /// A partial SizeAndActionsVec potentially doesn't cover all bit sizes,
- /// i.e. it's OK if it doesn't start from size 1.
- static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) {
- using namespace LegacyLegalizeActions;
- #ifndef NDEBUG
- // The sizes should be in increasing order
- int prev_size = -1;
- for(auto SizeAndAction: v) {
- assert(SizeAndAction.first > prev_size);
- prev_size = SizeAndAction.first;
- }
- // - for every Widen action, there should be a larger bitsize that
- // can be legalized towards (e.g. Legal, Lower, Libcall or Custom
- // action).
- // - for every Narrow action, there should be a smaller bitsize that
- // can be legalized towards.
- int SmallestNarrowIdx = -1;
- int LargestWidenIdx = -1;
- int SmallestLegalizableToSameSizeIdx = -1;
- int LargestLegalizableToSameSizeIdx = -1;
- for(size_t i=0; i<v.size(); ++i) {
- switch (v[i].second) {
- case FewerElements:
- case NarrowScalar:
- if (SmallestNarrowIdx == -1)
- SmallestNarrowIdx = i;
- break;
- case WidenScalar:
- case MoreElements:
- LargestWidenIdx = i;
- break;
- case Unsupported:
- break;
- default:
- if (SmallestLegalizableToSameSizeIdx == -1)
- SmallestLegalizableToSameSizeIdx = i;
- LargestLegalizableToSameSizeIdx = i;
- }
- }
- if (SmallestNarrowIdx != -1) {
- assert(SmallestLegalizableToSameSizeIdx != -1);
- assert(SmallestNarrowIdx > SmallestLegalizableToSameSizeIdx);
- }
- if (LargestWidenIdx != -1)
- assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx);
- #endif
- }
- /// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with
- /// from size 1.
- static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) {
- #ifndef NDEBUG
- // Data structure invariant: The first bit size must be size 1.
- assert(v.size() >= 1);
- assert(v[0].first == 1);
- checkPartialSizeAndActionsVector(v);
- #endif
- }
- /// Sets actions for all bit sizes on a particular generic opcode, type
- /// index and scalar or pointer type.
- void setActions(unsigned TypeIndex,
- SmallVector<SizeAndActionsVec, 1> &Actions,
- const SizeAndActionsVec &SizeAndActions) {
- checkFullSizeAndActionsVector(SizeAndActions);
- if (Actions.size() <= TypeIndex)
- Actions.resize(TypeIndex + 1);
- Actions[TypeIndex] = SizeAndActions;
- }
- static SizeAndAction findAction(const SizeAndActionsVec &Vec,
- const uint32_t Size);
- /// Returns the next action needed to get the scalar or pointer type closer
- /// to being legal
- /// E.g. findLegalAction({G_REM, 13}) should return
- /// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will
- /// probably be called, which should return (Lower, 32).
- /// This is assuming the setScalarAction on G_REM was something like:
- /// setScalarAction(G_REM, 0,
- /// {{1, WidenScalar}, // bit sizes [ 1, 31[
- /// {32, Lower}, // bit sizes [32, 33[
- /// {33, NarrowScalar} // bit sizes [65, +inf[
- /// });
- std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
- findScalarLegalAction(const InstrAspect &Aspect) const;
- /// Returns the next action needed towards legalizing the vector type.
- std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
- findVectorLegalAction(const InstrAspect &Aspect) const;
- static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
- static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
- // Data structures used temporarily during construction of legality data:
- using TypeMap = DenseMap<LLT, LegacyLegalizeActions::LegacyLegalizeAction>;
- SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];
- SmallVector<SizeChangeStrategy, 1>
- ScalarSizeChangeStrategies[LastOp - FirstOp + 1];
- SmallVector<SizeChangeStrategy, 1>
- VectorElementSizeChangeStrategies[LastOp - FirstOp + 1];
- bool TablesInitialized = false;
- // Data structures used by getAction:
- SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
- SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
- std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
- AddrSpace2PointerActions[LastOp - FirstOp + 1];
- std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
- NumElements2Actions[LastOp - FirstOp + 1];
- };
- } // end namespace llvm
- #endif // LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|