Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:24

0001 //===- llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h ------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 /// Interface for Targets to specify which operations they can successfully
0010 /// select and how the others should be expanded most efficiently.
0011 /// This implementation has been deprecated for a long time but it still in use
0012 /// in a few places.
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
0016 #define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
0017 
0018 #include "llvm/ADT/DenseMap.h"
0019 #include "llvm/CodeGen/TargetOpcodes.h"
0020 #include "llvm/CodeGenTypes/LowLevelType.h"
0021 #include <unordered_map>
0022 #include <vector>
0023 
0024 namespace llvm {
0025 struct LegalityQuery;
0026 
0027 namespace LegacyLegalizeActions {
0028 enum LegacyLegalizeAction : std::uint8_t {
0029   /// The operation is expected to be selectable directly by the target, and
0030   /// no transformation is necessary.
0031   Legal,
0032 
0033   /// The operation should be synthesized from multiple instructions acting on
0034   /// a narrower scalar base-type. For example a 64-bit add might be
0035   /// implemented in terms of 32-bit add-with-carry.
0036   NarrowScalar,
0037 
0038   /// The operation should be implemented in terms of a wider scalar
0039   /// base-type. For example a <2 x s8> add could be implemented as a <2
0040   /// x s32> add (ignoring the high bits).
0041   WidenScalar,
0042 
0043   /// The (vector) operation should be implemented by splitting it into
0044   /// sub-vectors where the operation is legal. For example a <8 x s64> add
0045   /// might be implemented as 4 separate <2 x s64> adds.
0046   FewerElements,
0047 
0048   /// The (vector) operation should be implemented by widening the input
0049   /// vector and ignoring the lanes added by doing so. For example <2 x i8> is
0050   /// rarely legal, but you might perform an <8 x i8> and then only look at
0051   /// the first two results.
0052   MoreElements,
0053 
0054   /// Perform the operation on a different, but equivalently sized type.
0055   Bitcast,
0056 
0057   /// The operation itself must be expressed in terms of simpler actions on
0058   /// this target. E.g. a SREM replaced by an SDIV and subtraction.
0059   Lower,
0060 
0061   /// The operation should be implemented as a call to some kind of runtime
0062   /// support library. For example this usually happens on machines that don't
0063   /// support floating-point operations natively.
0064   Libcall,
0065 
0066   /// The target wants to do something special with this combination of
0067   /// operand and type. A callback will be issued when it is needed.
0068   Custom,
0069 
0070   /// This operation is completely unsupported on the target. A programming
0071   /// error has occurred.
0072   Unsupported,
0073 
0074   /// Sentinel value for when no action was found in the specified table.
0075   NotFound,
0076 };
0077 } // end namespace LegacyLegalizeActions
0078 raw_ostream &operator<<(raw_ostream &OS,
0079                         LegacyLegalizeActions::LegacyLegalizeAction Action);
0080 
0081 /// Legalization is decided based on an instruction's opcode, which type slot
0082 /// we're considering, and what the existing type is. These aspects are gathered
0083 /// together for convenience in the InstrAspect class.
0084 struct InstrAspect {
0085   unsigned Opcode;
0086   unsigned Idx = 0;
0087   LLT Type;
0088 
0089   InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {}
0090   InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)
0091       : Opcode(Opcode), Idx(Idx), Type(Type) {}
0092 
0093   bool operator==(const InstrAspect &RHS) const {
0094     return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type;
0095   }
0096 };
0097 
0098 /// The result of a query. It either indicates a final answer of Legal or
0099 /// Unsupported or describes an action that must be taken to make an operation
0100 /// more legal.
0101 struct LegacyLegalizeActionStep {
0102   /// The action to take or the final answer.
0103   LegacyLegalizeActions::LegacyLegalizeAction Action;
0104   /// If describing an action, the type index to change. Otherwise zero.
0105   unsigned TypeIdx;
0106   /// If describing an action, the new type for TypeIdx. Otherwise LLT{}.
0107   LLT NewType;
0108 
0109   LegacyLegalizeActionStep(LegacyLegalizeActions::LegacyLegalizeAction Action,
0110                            unsigned TypeIdx, const LLT NewType)
0111       : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {}
0112 
0113   bool operator==(const LegacyLegalizeActionStep &RHS) const {
0114     return std::tie(Action, TypeIdx, NewType) ==
0115         std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType);
0116   }
0117 };
0118 
0119 
0120 class LegacyLegalizerInfo {
0121 public:
0122   using SizeAndAction =
0123       std::pair<uint16_t, LegacyLegalizeActions::LegacyLegalizeAction>;
0124   using SizeAndActionsVec = std::vector<SizeAndAction>;
0125   using SizeChangeStrategy =
0126       std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>;
0127 
0128   LegacyLegalizerInfo();
0129 
0130   static bool needsLegalizingToDifferentSize(
0131       const LegacyLegalizeActions::LegacyLegalizeAction Action) {
0132     using namespace LegacyLegalizeActions;
0133     switch (Action) {
0134     case NarrowScalar:
0135     case WidenScalar:
0136     case FewerElements:
0137     case MoreElements:
0138     case Unsupported:
0139       return true;
0140     default:
0141       return false;
0142     }
0143   }
0144 
0145   /// Compute any ancillary tables needed to quickly decide how an operation
0146   /// should be handled. This must be called after all "set*Action"methods but
0147   /// before any query is made or incorrect results may be returned.
0148   void computeTables();
0149 
0150   /// More friendly way to set an action for common types that have an LLT
0151   /// representation.
0152   /// The LegacyLegalizeAction must be one for which
0153   /// NeedsLegalizingToDifferentSize returns false.
0154   void setAction(const InstrAspect &Aspect,
0155                  LegacyLegalizeActions::LegacyLegalizeAction Action) {
0156     assert(!needsLegalizingToDifferentSize(Action));
0157     TablesInitialized = false;
0158     const unsigned OpcodeIdx = Aspect.Opcode - FirstOp;
0159     if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx)
0160       SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1);
0161     SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action;
0162   }
0163 
0164   /// The setAction calls record the non-size-changing legalization actions
0165   /// to take on specificly-sized types. The SizeChangeStrategy defines what
0166   /// to do when the size of the type needs to be changed to reach a legally
0167   /// sized type (i.e., one that was defined through a setAction call).
0168   /// e.g.
0169   /// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal);
0170   /// setLegalizeScalarToDifferentSizeStrategy(
0171   ///   G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
0172   /// will end up defining getAction({G_ADD, 0, T}) to return the following
0173   /// actions for different scalar types T:
0174   ///  LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)}
0175   ///  LLT::scalar(32):                 {Legal, 0, LLT::scalar(32)}
0176   ///  LLT::scalar(33)..:               {NarrowScalar, 0, LLT::scalar(32)}
0177   ///
0178   /// If no SizeChangeAction gets defined, through this function,
0179   /// the default is unsupportedForDifferentSizes.
0180   void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode,
0181                                                 const unsigned TypeIdx,
0182                                                 SizeChangeStrategy S) {
0183     const unsigned OpcodeIdx = Opcode - FirstOp;
0184     if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
0185       ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
0186     ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
0187   }
0188 
0189   /// See also setLegalizeScalarToDifferentSizeStrategy.
0190   /// This function allows to set the SizeChangeStrategy for vector elements.
0191   void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode,
0192                                                        const unsigned TypeIdx,
0193                                                        SizeChangeStrategy S) {
0194     const unsigned OpcodeIdx = Opcode - FirstOp;
0195     if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
0196       VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
0197     VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
0198   }
0199 
0200   /// A SizeChangeStrategy for the common case where legalization for a
0201   /// particular operation consists of only supporting a specific set of type
0202   /// sizes. E.g.
0203   ///   setAction ({G_DIV, 0, LLT::scalar(32)}, Legal);
0204   ///   setAction ({G_DIV, 0, LLT::scalar(64)}, Legal);
0205   ///   setLegalizeScalarToDifferentSizeStrategy(
0206   ///     G_DIV, 0, unsupportedForDifferentSizes);
0207   /// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64,
0208   /// and Unsupported for all other scalar types T.
0209   static SizeAndActionsVec
0210   unsupportedForDifferentSizes(const SizeAndActionsVec &v) {
0211     using namespace LegacyLegalizeActions;
0212     return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported,
0213                                                      Unsupported);
0214   }
0215 
0216   /// A SizeChangeStrategy for the common case where legalization for a
0217   /// particular operation consists of widening the type to a large legal type,
0218   /// unless there is no such type and then instead it should be narrowed to the
0219   /// largest legal type.
0220   static SizeAndActionsVec
0221   widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) {
0222     using namespace LegacyLegalizeActions;
0223     assert(v.size() > 0 &&
0224            "At least one size that can be legalized towards is needed"
0225            " for this SizeChangeStrategy");
0226     return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
0227                                                      NarrowScalar);
0228   }
0229 
0230   static SizeAndActionsVec
0231   widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) {
0232     using namespace LegacyLegalizeActions;
0233     return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
0234                                                      Unsupported);
0235   }
0236 
0237   static SizeAndActionsVec
0238   narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) {
0239     using namespace LegacyLegalizeActions;
0240     return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
0241                                                        Unsupported);
0242   }
0243 
0244   /// A SizeChangeStrategy for the common case where legalization for a
0245   /// particular vector operation consists of having more elements in the
0246   /// vector, to a type that is legal. Unless there is no such type and then
0247   /// instead it should be legalized towards the widest vector that's still
0248   /// legal. E.g.
0249   ///   setAction({G_ADD, LLT::vector(8, 8)}, Legal);
0250   ///   setAction({G_ADD, LLT::vector(16, 8)}, Legal);
0251   ///   setAction({G_ADD, LLT::vector(2, 32)}, Legal);
0252   ///   setAction({G_ADD, LLT::vector(4, 32)}, Legal);
0253   ///   setLegalizeVectorElementToDifferentSizeStrategy(
0254   ///     G_ADD, 0, moreToWiderTypesAndLessToWidest);
0255   /// will result in the following getAction results:
0256   ///   * getAction({G_ADD, LLT::vector(8,8)}) returns
0257   ///       (Legal, vector(8,8)).
0258   ///   * getAction({G_ADD, LLT::vector(9,8)}) returns
0259   ///       (MoreElements, vector(16,8)).
0260   ///   * getAction({G_ADD, LLT::vector(8,32)}) returns
0261   ///       (FewerElements, vector(4,32)).
0262   static SizeAndActionsVec
0263   moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) {
0264     using namespace LegacyLegalizeActions;
0265     return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements,
0266                                                      FewerElements);
0267   }
0268 
0269   /// Helper function to implement many typical SizeChangeStrategy functions.
0270   static SizeAndActionsVec increaseToLargerTypesAndDecreaseToLargest(
0271       const SizeAndActionsVec &v,
0272       LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction,
0273       LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction);
0274   /// Helper function to implement many typical SizeChangeStrategy functions.
0275   static SizeAndActionsVec decreaseToSmallerTypesAndIncreaseToSmallest(
0276       const SizeAndActionsVec &v,
0277       LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction,
0278       LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction);
0279 
0280   LegacyLegalizeActionStep getAction(const LegalityQuery &Query) const;
0281 
0282   unsigned getOpcodeIdxForOpcode(unsigned Opcode) const;
0283 
0284 private:
0285   /// Determine what action should be taken to legalize the given generic
0286   /// instruction opcode, type-index and type. Requires computeTables to have
0287   /// been called.
0288   ///
0289   /// \returns a pair consisting of the kind of legalization that should be
0290   /// performed and the destination type.
0291   std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
0292   getAspectAction(const InstrAspect &Aspect) const;
0293 
0294   /// The SizeAndActionsVec is a representation mapping between all natural
0295   /// numbers and an Action. The natural number represents the bit size of
0296   /// the InstrAspect. For example, for a target with native support for 32-bit
0297   /// and 64-bit additions, you'd express that as:
0298   /// setScalarAction(G_ADD, 0,
0299   ///           {{1, WidenScalar},  // bit sizes [ 1, 31[
0300   ///            {32, Legal},       // bit sizes [32, 33[
0301   ///            {33, WidenScalar}, // bit sizes [33, 64[
0302   ///            {64, Legal},       // bit sizes [64, 65[
0303   ///            {65, NarrowScalar} // bit sizes [65, +inf[
0304   ///           });
0305   /// It may be that only 64-bit pointers are supported on your target:
0306   /// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1),
0307   ///           {{1, Unsupported},  // bit sizes [ 1, 63[
0308   ///            {64, Legal},       // bit sizes [64, 65[
0309   ///            {65, Unsupported}, // bit sizes [65, +inf[
0310   ///           });
0311   void setScalarAction(const unsigned Opcode, const unsigned TypeIndex,
0312                        const SizeAndActionsVec &SizeAndActions) {
0313     const unsigned OpcodeIdx = Opcode - FirstOp;
0314     SmallVector<SizeAndActionsVec, 1> &Actions = ScalarActions[OpcodeIdx];
0315     setActions(TypeIndex, Actions, SizeAndActions);
0316   }
0317   void setPointerAction(const unsigned Opcode, const unsigned TypeIndex,
0318                         const unsigned AddressSpace,
0319                         const SizeAndActionsVec &SizeAndActions) {
0320     const unsigned OpcodeIdx = Opcode - FirstOp;
0321     SmallVector<SizeAndActionsVec, 1> &Actions =
0322         AddrSpace2PointerActions[OpcodeIdx][AddressSpace];
0323     setActions(TypeIndex, Actions, SizeAndActions);
0324   }
0325 
0326   /// If an operation on a given vector type (say <M x iN>) isn't explicitly
0327   /// specified, we proceed in 2 stages. First we legalize the underlying scalar
0328   /// (so that there's at least one legal vector with that scalar), then we
0329   /// adjust the number of elements in the vector so that it is legal. The
0330   /// desired action in the first step is controlled by this function.
0331   void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex,
0332                                const SizeAndActionsVec &SizeAndActions) {
0333     unsigned OpcodeIdx = Opcode - FirstOp;
0334     SmallVector<SizeAndActionsVec, 1> &Actions =
0335         ScalarInVectorActions[OpcodeIdx];
0336     setActions(TypeIndex, Actions, SizeAndActions);
0337   }
0338 
0339   /// See also setScalarInVectorAction.
0340   /// This function let's you specify the number of elements in a vector that
0341   /// are legal for a legal element size.
0342   void setVectorNumElementAction(const unsigned Opcode,
0343                                  const unsigned TypeIndex,
0344                                  const unsigned ElementSize,
0345                                  const SizeAndActionsVec &SizeAndActions) {
0346     const unsigned OpcodeIdx = Opcode - FirstOp;
0347     SmallVector<SizeAndActionsVec, 1> &Actions =
0348         NumElements2Actions[OpcodeIdx][ElementSize];
0349     setActions(TypeIndex, Actions, SizeAndActions);
0350   }
0351 
0352   /// A partial SizeAndActionsVec potentially doesn't cover all bit sizes,
0353   /// i.e. it's OK if it doesn't start from size 1.
0354   static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) {
0355     using namespace LegacyLegalizeActions;
0356 #ifndef NDEBUG
0357     // The sizes should be in increasing order
0358     int prev_size = -1;
0359     for(auto SizeAndAction: v) {
0360       assert(SizeAndAction.first > prev_size);
0361       prev_size = SizeAndAction.first;
0362     }
0363     // - for every Widen action, there should be a larger bitsize that
0364     //   can be legalized towards (e.g. Legal, Lower, Libcall or Custom
0365     //   action).
0366     // - for every Narrow action, there should be a smaller bitsize that
0367     //   can be legalized towards.
0368     int SmallestNarrowIdx = -1;
0369     int LargestWidenIdx = -1;
0370     int SmallestLegalizableToSameSizeIdx = -1;
0371     int LargestLegalizableToSameSizeIdx = -1;
0372     for(size_t i=0; i<v.size(); ++i) {
0373       switch (v[i].second) {
0374         case FewerElements:
0375         case NarrowScalar:
0376           if (SmallestNarrowIdx == -1)
0377             SmallestNarrowIdx = i;
0378           break;
0379         case WidenScalar:
0380         case MoreElements:
0381           LargestWidenIdx = i;
0382           break;
0383         case Unsupported:
0384           break;
0385         default:
0386           if (SmallestLegalizableToSameSizeIdx == -1)
0387             SmallestLegalizableToSameSizeIdx = i;
0388           LargestLegalizableToSameSizeIdx = i;
0389       }
0390     }
0391     if (SmallestNarrowIdx != -1) {
0392       assert(SmallestLegalizableToSameSizeIdx != -1);
0393       assert(SmallestNarrowIdx > SmallestLegalizableToSameSizeIdx);
0394     }
0395     if (LargestWidenIdx != -1)
0396       assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx);
0397 #endif
0398   }
0399 
0400   /// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with
0401   /// from size 1.
0402   static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) {
0403 #ifndef NDEBUG
0404     // Data structure invariant: The first bit size must be size 1.
0405     assert(v.size() >= 1);
0406     assert(v[0].first == 1);
0407     checkPartialSizeAndActionsVector(v);
0408 #endif
0409   }
0410 
0411   /// Sets actions for all bit sizes on a particular generic opcode, type
0412   /// index and scalar or pointer type.
0413   void setActions(unsigned TypeIndex,
0414                   SmallVector<SizeAndActionsVec, 1> &Actions,
0415                   const SizeAndActionsVec &SizeAndActions) {
0416     checkFullSizeAndActionsVector(SizeAndActions);
0417     if (Actions.size() <= TypeIndex)
0418       Actions.resize(TypeIndex + 1);
0419     Actions[TypeIndex] = SizeAndActions;
0420   }
0421 
0422   static SizeAndAction findAction(const SizeAndActionsVec &Vec,
0423                                   const uint32_t Size);
0424 
0425   /// Returns the next action needed to get the scalar or pointer type closer
0426   /// to being legal
0427   /// E.g. findLegalAction({G_REM, 13}) should return
0428   /// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will
0429   /// probably be called, which should return (Lower, 32).
0430   /// This is assuming the setScalarAction on G_REM was something like:
0431   /// setScalarAction(G_REM, 0,
0432   ///           {{1, WidenScalar},  // bit sizes [ 1, 31[
0433   ///            {32, Lower},       // bit sizes [32, 33[
0434   ///            {33, NarrowScalar} // bit sizes [65, +inf[
0435   ///           });
0436   std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
0437   findScalarLegalAction(const InstrAspect &Aspect) const;
0438 
0439   /// Returns the next action needed towards legalizing the vector type.
0440   std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
0441   findVectorLegalAction(const InstrAspect &Aspect) const;
0442 
0443   static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
0444   static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
0445 
0446   // Data structures used temporarily during construction of legality data:
0447   using TypeMap = DenseMap<LLT, LegacyLegalizeActions::LegacyLegalizeAction>;
0448   SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];
0449   SmallVector<SizeChangeStrategy, 1>
0450       ScalarSizeChangeStrategies[LastOp - FirstOp + 1];
0451   SmallVector<SizeChangeStrategy, 1>
0452       VectorElementSizeChangeStrategies[LastOp - FirstOp + 1];
0453   bool TablesInitialized = false;
0454 
0455   // Data structures used by getAction:
0456   SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
0457   SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
0458   std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
0459       AddrSpace2PointerActions[LastOp - FirstOp + 1];
0460   std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
0461       NumElements2Actions[LastOp - FirstOp + 1];
0462 };
0463 
0464 } // end namespace llvm
0465 
0466 #endif // LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H