1fe6060f1SDimitry Andric //===- llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h ------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// \file 9fe6060f1SDimitry Andric /// Interface for Targets to specify which operations they can successfully 10fe6060f1SDimitry Andric /// select and how the others should be expanded most efficiently. 11fe6060f1SDimitry Andric /// This implementation has been deprecated for a long time but it still in use 12fe6060f1SDimitry Andric /// in a few places. 13fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 14fe6060f1SDimitry Andric 15fe6060f1SDimitry Andric #ifndef LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H 16fe6060f1SDimitry Andric #define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H 17fe6060f1SDimitry Andric 18fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h" 19fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 20*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/LowLevelType.h" 21fe6060f1SDimitry Andric #include <unordered_map> 225f757f3fSDimitry Andric #include <vector> 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric namespace llvm { 25fe6060f1SDimitry Andric struct LegalityQuery; 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric namespace LegacyLegalizeActions { 28fe6060f1SDimitry Andric enum LegacyLegalizeAction : std::uint8_t { 29fe6060f1SDimitry Andric /// The operation is expected to be selectable directly by the target, and 30fe6060f1SDimitry Andric /// no transformation is necessary. 31fe6060f1SDimitry Andric Legal, 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric /// The operation should be synthesized from multiple instructions acting on 34fe6060f1SDimitry Andric /// a narrower scalar base-type. For example a 64-bit add might be 35fe6060f1SDimitry Andric /// implemented in terms of 32-bit add-with-carry. 36fe6060f1SDimitry Andric NarrowScalar, 37fe6060f1SDimitry Andric 38fe6060f1SDimitry Andric /// The operation should be implemented in terms of a wider scalar 39fe6060f1SDimitry Andric /// base-type. For example a <2 x s8> add could be implemented as a <2 40fe6060f1SDimitry Andric /// x s32> add (ignoring the high bits). 41fe6060f1SDimitry Andric WidenScalar, 42fe6060f1SDimitry Andric 43fe6060f1SDimitry Andric /// The (vector) operation should be implemented by splitting it into 44fe6060f1SDimitry Andric /// sub-vectors where the operation is legal. For example a <8 x s64> add 45fe6060f1SDimitry Andric /// might be implemented as 4 separate <2 x s64> adds. 46fe6060f1SDimitry Andric FewerElements, 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric /// The (vector) operation should be implemented by widening the input 49fe6060f1SDimitry Andric /// vector and ignoring the lanes added by doing so. For example <2 x i8> is 50fe6060f1SDimitry Andric /// rarely legal, but you might perform an <8 x i8> and then only look at 51fe6060f1SDimitry Andric /// the first two results. 52fe6060f1SDimitry Andric MoreElements, 53fe6060f1SDimitry Andric 54fe6060f1SDimitry Andric /// Perform the operation on a different, but equivalently sized type. 55fe6060f1SDimitry Andric Bitcast, 56fe6060f1SDimitry Andric 57fe6060f1SDimitry Andric /// The operation itself must be expressed in terms of simpler actions on 58fe6060f1SDimitry Andric /// this target. E.g. a SREM replaced by an SDIV and subtraction. 59fe6060f1SDimitry Andric Lower, 60fe6060f1SDimitry Andric 61fe6060f1SDimitry Andric /// The operation should be implemented as a call to some kind of runtime 62fe6060f1SDimitry Andric /// support library. For example this usually happens on machines that don't 63fe6060f1SDimitry Andric /// support floating-point operations natively. 64fe6060f1SDimitry Andric Libcall, 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric /// The target wants to do something special with this combination of 67fe6060f1SDimitry Andric /// operand and type. A callback will be issued when it is needed. 68fe6060f1SDimitry Andric Custom, 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric /// This operation is completely unsupported on the target. A programming 71fe6060f1SDimitry Andric /// error has occurred. 72fe6060f1SDimitry Andric Unsupported, 73fe6060f1SDimitry Andric 74fe6060f1SDimitry Andric /// Sentinel value for when no action was found in the specified table. 75fe6060f1SDimitry Andric NotFound, 76fe6060f1SDimitry Andric }; 77fe6060f1SDimitry Andric } // end namespace LegacyLegalizeActions 78fe6060f1SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, 79fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction Action); 80fe6060f1SDimitry Andric 81fe6060f1SDimitry Andric /// Legalization is decided based on an instruction's opcode, which type slot 82fe6060f1SDimitry Andric /// we're considering, and what the existing type is. These aspects are gathered 83fe6060f1SDimitry Andric /// together for convenience in the InstrAspect class. 84fe6060f1SDimitry Andric struct InstrAspect { 85fe6060f1SDimitry Andric unsigned Opcode; 86fe6060f1SDimitry Andric unsigned Idx = 0; 87fe6060f1SDimitry Andric LLT Type; 88fe6060f1SDimitry Andric InstrAspectInstrAspect89fe6060f1SDimitry Andric InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {} InstrAspectInstrAspect90fe6060f1SDimitry Andric InstrAspect(unsigned Opcode, unsigned Idx, LLT Type) 91fe6060f1SDimitry Andric : Opcode(Opcode), Idx(Idx), Type(Type) {} 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric bool operator==(const InstrAspect &RHS) const { 94fe6060f1SDimitry Andric return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type; 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric }; 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric /// The result of a query. It either indicates a final answer of Legal or 99fe6060f1SDimitry Andric /// Unsupported or describes an action that must be taken to make an operation 100fe6060f1SDimitry Andric /// more legal. 101fe6060f1SDimitry Andric struct LegacyLegalizeActionStep { 102fe6060f1SDimitry Andric /// The action to take or the final answer. 103fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction Action; 104fe6060f1SDimitry Andric /// If describing an action, the type index to change. Otherwise zero. 105fe6060f1SDimitry Andric unsigned TypeIdx; 106fe6060f1SDimitry Andric /// If describing an action, the new type for TypeIdx. Otherwise LLT{}. 107fe6060f1SDimitry Andric LLT NewType; 108fe6060f1SDimitry Andric LegacyLegalizeActionStepLegacyLegalizeActionStep109fe6060f1SDimitry Andric LegacyLegalizeActionStep(LegacyLegalizeActions::LegacyLegalizeAction Action, 110fe6060f1SDimitry Andric unsigned TypeIdx, const LLT NewType) 111fe6060f1SDimitry Andric : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {} 112fe6060f1SDimitry Andric 113fe6060f1SDimitry Andric bool operator==(const LegacyLegalizeActionStep &RHS) const { 114fe6060f1SDimitry Andric return std::tie(Action, TypeIdx, NewType) == 115fe6060f1SDimitry Andric std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType); 116fe6060f1SDimitry Andric } 117fe6060f1SDimitry Andric }; 118fe6060f1SDimitry Andric 119fe6060f1SDimitry Andric 120fe6060f1SDimitry Andric class LegacyLegalizerInfo { 121fe6060f1SDimitry Andric public: 122fe6060f1SDimitry Andric using SizeAndAction = 123fe6060f1SDimitry Andric std::pair<uint16_t, LegacyLegalizeActions::LegacyLegalizeAction>; 124fe6060f1SDimitry Andric using SizeAndActionsVec = std::vector<SizeAndAction>; 125fe6060f1SDimitry Andric using SizeChangeStrategy = 126fe6060f1SDimitry Andric std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>; 127fe6060f1SDimitry Andric 128fe6060f1SDimitry Andric LegacyLegalizerInfo(); 129fe6060f1SDimitry Andric needsLegalizingToDifferentSize(const LegacyLegalizeActions::LegacyLegalizeAction Action)130fe6060f1SDimitry Andric static bool needsLegalizingToDifferentSize( 131fe6060f1SDimitry Andric const LegacyLegalizeActions::LegacyLegalizeAction Action) { 132fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 133fe6060f1SDimitry Andric switch (Action) { 134fe6060f1SDimitry Andric case NarrowScalar: 135fe6060f1SDimitry Andric case WidenScalar: 136fe6060f1SDimitry Andric case FewerElements: 137fe6060f1SDimitry Andric case MoreElements: 138fe6060f1SDimitry Andric case Unsupported: 139fe6060f1SDimitry Andric return true; 140fe6060f1SDimitry Andric default: 141fe6060f1SDimitry Andric return false; 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric /// Compute any ancillary tables needed to quickly decide how an operation 146fe6060f1SDimitry Andric /// should be handled. This must be called after all "set*Action"methods but 147fe6060f1SDimitry Andric /// before any query is made or incorrect results may be returned. 148fe6060f1SDimitry Andric void computeTables(); 149fe6060f1SDimitry Andric 150fe6060f1SDimitry Andric /// More friendly way to set an action for common types that have an LLT 151fe6060f1SDimitry Andric /// representation. 152fe6060f1SDimitry Andric /// The LegacyLegalizeAction must be one for which 153fe6060f1SDimitry Andric /// NeedsLegalizingToDifferentSize returns false. setAction(const InstrAspect & Aspect,LegacyLegalizeActions::LegacyLegalizeAction Action)154fe6060f1SDimitry Andric void setAction(const InstrAspect &Aspect, 155fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction Action) { 156fe6060f1SDimitry Andric assert(!needsLegalizingToDifferentSize(Action)); 157fe6060f1SDimitry Andric TablesInitialized = false; 158fe6060f1SDimitry Andric const unsigned OpcodeIdx = Aspect.Opcode - FirstOp; 159fe6060f1SDimitry Andric if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx) 160fe6060f1SDimitry Andric SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1); 161fe6060f1SDimitry Andric SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action; 162fe6060f1SDimitry Andric } 163fe6060f1SDimitry Andric 164fe6060f1SDimitry Andric /// The setAction calls record the non-size-changing legalization actions 165fe6060f1SDimitry Andric /// to take on specificly-sized types. The SizeChangeStrategy defines what 166fe6060f1SDimitry Andric /// to do when the size of the type needs to be changed to reach a legally 167fe6060f1SDimitry Andric /// sized type (i.e., one that was defined through a setAction call). 168fe6060f1SDimitry Andric /// e.g. 169fe6060f1SDimitry Andric /// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal); 170fe6060f1SDimitry Andric /// setLegalizeScalarToDifferentSizeStrategy( 171fe6060f1SDimitry Andric /// G_ADD, 0, widenToLargerTypesAndNarrowToLargest); 172fe6060f1SDimitry Andric /// will end up defining getAction({G_ADD, 0, T}) to return the following 173fe6060f1SDimitry Andric /// actions for different scalar types T: 174fe6060f1SDimitry Andric /// LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)} 175fe6060f1SDimitry Andric /// LLT::scalar(32): {Legal, 0, LLT::scalar(32)} 176fe6060f1SDimitry Andric /// LLT::scalar(33)..: {NarrowScalar, 0, LLT::scalar(32)} 177fe6060f1SDimitry Andric /// 178fe6060f1SDimitry Andric /// If no SizeChangeAction gets defined, through this function, 179fe6060f1SDimitry Andric /// the default is unsupportedForDifferentSizes. setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode,const unsigned TypeIdx,SizeChangeStrategy S)180fe6060f1SDimitry Andric void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode, 181fe6060f1SDimitry Andric const unsigned TypeIdx, 182fe6060f1SDimitry Andric SizeChangeStrategy S) { 183fe6060f1SDimitry Andric const unsigned OpcodeIdx = Opcode - FirstOp; 184fe6060f1SDimitry Andric if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx) 185fe6060f1SDimitry Andric ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1); 186fe6060f1SDimitry Andric ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S; 187fe6060f1SDimitry Andric } 188fe6060f1SDimitry Andric 189fe6060f1SDimitry Andric /// See also setLegalizeScalarToDifferentSizeStrategy. 190fe6060f1SDimitry Andric /// This function allows to set the SizeChangeStrategy for vector elements. setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode,const unsigned TypeIdx,SizeChangeStrategy S)191fe6060f1SDimitry Andric void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode, 192fe6060f1SDimitry Andric const unsigned TypeIdx, 193fe6060f1SDimitry Andric SizeChangeStrategy S) { 194fe6060f1SDimitry Andric const unsigned OpcodeIdx = Opcode - FirstOp; 195fe6060f1SDimitry Andric if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx) 196fe6060f1SDimitry Andric VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1); 197fe6060f1SDimitry Andric VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S; 198fe6060f1SDimitry Andric } 199fe6060f1SDimitry Andric 200fe6060f1SDimitry Andric /// A SizeChangeStrategy for the common case where legalization for a 201fe6060f1SDimitry Andric /// particular operation consists of only supporting a specific set of type 202fe6060f1SDimitry Andric /// sizes. E.g. 203fe6060f1SDimitry Andric /// setAction ({G_DIV, 0, LLT::scalar(32)}, Legal); 204fe6060f1SDimitry Andric /// setAction ({G_DIV, 0, LLT::scalar(64)}, Legal); 205fe6060f1SDimitry Andric /// setLegalizeScalarToDifferentSizeStrategy( 206fe6060f1SDimitry Andric /// G_DIV, 0, unsupportedForDifferentSizes); 207fe6060f1SDimitry Andric /// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64, 208fe6060f1SDimitry Andric /// and Unsupported for all other scalar types T. 209fe6060f1SDimitry Andric static SizeAndActionsVec unsupportedForDifferentSizes(const SizeAndActionsVec & v)210fe6060f1SDimitry Andric unsupportedForDifferentSizes(const SizeAndActionsVec &v) { 211fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 212fe6060f1SDimitry Andric return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported, 213fe6060f1SDimitry Andric Unsupported); 214fe6060f1SDimitry Andric } 215fe6060f1SDimitry Andric 216fe6060f1SDimitry Andric /// A SizeChangeStrategy for the common case where legalization for a 217fe6060f1SDimitry Andric /// particular operation consists of widening the type to a large legal type, 218fe6060f1SDimitry Andric /// unless there is no such type and then instead it should be narrowed to the 219fe6060f1SDimitry Andric /// largest legal type. 220fe6060f1SDimitry Andric static SizeAndActionsVec widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec & v)221fe6060f1SDimitry Andric widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) { 222fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 223fe6060f1SDimitry Andric assert(v.size() > 0 && 224fe6060f1SDimitry Andric "At least one size that can be legalized towards is needed" 225fe6060f1SDimitry Andric " for this SizeChangeStrategy"); 226fe6060f1SDimitry Andric return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar, 227fe6060f1SDimitry Andric NarrowScalar); 228fe6060f1SDimitry Andric } 229fe6060f1SDimitry Andric 230fe6060f1SDimitry Andric static SizeAndActionsVec widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec & v)231fe6060f1SDimitry Andric widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) { 232fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 233fe6060f1SDimitry Andric return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar, 234fe6060f1SDimitry Andric Unsupported); 235fe6060f1SDimitry Andric } 236fe6060f1SDimitry Andric 237fe6060f1SDimitry Andric static SizeAndActionsVec narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec & v)238fe6060f1SDimitry Andric narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) { 239fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 240fe6060f1SDimitry Andric return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar, 241fe6060f1SDimitry Andric Unsupported); 242fe6060f1SDimitry Andric } 243fe6060f1SDimitry Andric 244fe6060f1SDimitry Andric /// A SizeChangeStrategy for the common case where legalization for a 245fe6060f1SDimitry Andric /// particular vector operation consists of having more elements in the 246fe6060f1SDimitry Andric /// vector, to a type that is legal. Unless there is no such type and then 247fe6060f1SDimitry Andric /// instead it should be legalized towards the widest vector that's still 248fe6060f1SDimitry Andric /// legal. E.g. 249fe6060f1SDimitry Andric /// setAction({G_ADD, LLT::vector(8, 8)}, Legal); 250fe6060f1SDimitry Andric /// setAction({G_ADD, LLT::vector(16, 8)}, Legal); 251fe6060f1SDimitry Andric /// setAction({G_ADD, LLT::vector(2, 32)}, Legal); 252fe6060f1SDimitry Andric /// setAction({G_ADD, LLT::vector(4, 32)}, Legal); 253fe6060f1SDimitry Andric /// setLegalizeVectorElementToDifferentSizeStrategy( 254fe6060f1SDimitry Andric /// G_ADD, 0, moreToWiderTypesAndLessToWidest); 255fe6060f1SDimitry Andric /// will result in the following getAction results: 256fe6060f1SDimitry Andric /// * getAction({G_ADD, LLT::vector(8,8)}) returns 257fe6060f1SDimitry Andric /// (Legal, vector(8,8)). 258fe6060f1SDimitry Andric /// * getAction({G_ADD, LLT::vector(9,8)}) returns 259fe6060f1SDimitry Andric /// (MoreElements, vector(16,8)). 260fe6060f1SDimitry Andric /// * getAction({G_ADD, LLT::vector(8,32)}) returns 261fe6060f1SDimitry Andric /// (FewerElements, vector(4,32)). 262fe6060f1SDimitry Andric static SizeAndActionsVec moreToWiderTypesAndLessToWidest(const SizeAndActionsVec & v)263fe6060f1SDimitry Andric moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) { 264fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 265fe6060f1SDimitry Andric return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements, 266fe6060f1SDimitry Andric FewerElements); 267fe6060f1SDimitry Andric } 268fe6060f1SDimitry Andric 269fe6060f1SDimitry Andric /// Helper function to implement many typical SizeChangeStrategy functions. 270fe6060f1SDimitry Andric static SizeAndActionsVec increaseToLargerTypesAndDecreaseToLargest( 271fe6060f1SDimitry Andric const SizeAndActionsVec &v, 272fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction, 273fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction); 274fe6060f1SDimitry Andric /// Helper function to implement many typical SizeChangeStrategy functions. 275fe6060f1SDimitry Andric static SizeAndActionsVec decreaseToSmallerTypesAndIncreaseToSmallest( 276fe6060f1SDimitry Andric const SizeAndActionsVec &v, 277fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction, 278fe6060f1SDimitry Andric LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction); 279fe6060f1SDimitry Andric 280fe6060f1SDimitry Andric LegacyLegalizeActionStep getAction(const LegalityQuery &Query) const; 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric unsigned getOpcodeIdxForOpcode(unsigned Opcode) const; 283fe6060f1SDimitry Andric 284fe6060f1SDimitry Andric private: 285fe6060f1SDimitry Andric /// Determine what action should be taken to legalize the given generic 286fe6060f1SDimitry Andric /// instruction opcode, type-index and type. Requires computeTables to have 287fe6060f1SDimitry Andric /// been called. 288fe6060f1SDimitry Andric /// 289fe6060f1SDimitry Andric /// \returns a pair consisting of the kind of legalization that should be 290fe6060f1SDimitry Andric /// performed and the destination type. 291fe6060f1SDimitry Andric std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT> 292fe6060f1SDimitry Andric getAspectAction(const InstrAspect &Aspect) const; 293fe6060f1SDimitry Andric 294fe6060f1SDimitry Andric /// The SizeAndActionsVec is a representation mapping between all natural 295fe6060f1SDimitry Andric /// numbers and an Action. The natural number represents the bit size of 296fe6060f1SDimitry Andric /// the InstrAspect. For example, for a target with native support for 32-bit 297fe6060f1SDimitry Andric /// and 64-bit additions, you'd express that as: 298fe6060f1SDimitry Andric /// setScalarAction(G_ADD, 0, 299fe6060f1SDimitry Andric /// {{1, WidenScalar}, // bit sizes [ 1, 31[ 300fe6060f1SDimitry Andric /// {32, Legal}, // bit sizes [32, 33[ 301fe6060f1SDimitry Andric /// {33, WidenScalar}, // bit sizes [33, 64[ 302fe6060f1SDimitry Andric /// {64, Legal}, // bit sizes [64, 65[ 303fe6060f1SDimitry Andric /// {65, NarrowScalar} // bit sizes [65, +inf[ 304fe6060f1SDimitry Andric /// }); 305fe6060f1SDimitry Andric /// It may be that only 64-bit pointers are supported on your target: 306fe6060f1SDimitry Andric /// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1), 307fe6060f1SDimitry Andric /// {{1, Unsupported}, // bit sizes [ 1, 63[ 308fe6060f1SDimitry Andric /// {64, Legal}, // bit sizes [64, 65[ 309fe6060f1SDimitry Andric /// {65, Unsupported}, // bit sizes [65, +inf[ 310fe6060f1SDimitry Andric /// }); setScalarAction(const unsigned Opcode,const unsigned TypeIndex,const SizeAndActionsVec & SizeAndActions)311fe6060f1SDimitry Andric void setScalarAction(const unsigned Opcode, const unsigned TypeIndex, 312fe6060f1SDimitry Andric const SizeAndActionsVec &SizeAndActions) { 313fe6060f1SDimitry Andric const unsigned OpcodeIdx = Opcode - FirstOp; 314fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> &Actions = ScalarActions[OpcodeIdx]; 315fe6060f1SDimitry Andric setActions(TypeIndex, Actions, SizeAndActions); 316fe6060f1SDimitry Andric } setPointerAction(const unsigned Opcode,const unsigned TypeIndex,const unsigned AddressSpace,const SizeAndActionsVec & SizeAndActions)317fe6060f1SDimitry Andric void setPointerAction(const unsigned Opcode, const unsigned TypeIndex, 318fe6060f1SDimitry Andric const unsigned AddressSpace, 319fe6060f1SDimitry Andric const SizeAndActionsVec &SizeAndActions) { 320fe6060f1SDimitry Andric const unsigned OpcodeIdx = Opcode - FirstOp; 321fe6060f1SDimitry Andric if (AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace) == 322fe6060f1SDimitry Andric AddrSpace2PointerActions[OpcodeIdx].end()) 323fe6060f1SDimitry Andric AddrSpace2PointerActions[OpcodeIdx][AddressSpace] = {{}}; 324fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> &Actions = 325fe6060f1SDimitry Andric AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second; 326fe6060f1SDimitry Andric setActions(TypeIndex, Actions, SizeAndActions); 327fe6060f1SDimitry Andric } 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric /// If an operation on a given vector type (say <M x iN>) isn't explicitly 330fe6060f1SDimitry Andric /// specified, we proceed in 2 stages. First we legalize the underlying scalar 331fe6060f1SDimitry Andric /// (so that there's at least one legal vector with that scalar), then we 332fe6060f1SDimitry Andric /// adjust the number of elements in the vector so that it is legal. The 333fe6060f1SDimitry Andric /// desired action in the first step is controlled by this function. setScalarInVectorAction(const unsigned Opcode,const unsigned TypeIndex,const SizeAndActionsVec & SizeAndActions)334fe6060f1SDimitry Andric void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex, 335fe6060f1SDimitry Andric const SizeAndActionsVec &SizeAndActions) { 336fe6060f1SDimitry Andric unsigned OpcodeIdx = Opcode - FirstOp; 337fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> &Actions = 338fe6060f1SDimitry Andric ScalarInVectorActions[OpcodeIdx]; 339fe6060f1SDimitry Andric setActions(TypeIndex, Actions, SizeAndActions); 340fe6060f1SDimitry Andric } 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric /// See also setScalarInVectorAction. 343fe6060f1SDimitry Andric /// This function let's you specify the number of elements in a vector that 344fe6060f1SDimitry Andric /// are legal for a legal element size. setVectorNumElementAction(const unsigned Opcode,const unsigned TypeIndex,const unsigned ElementSize,const SizeAndActionsVec & SizeAndActions)345fe6060f1SDimitry Andric void setVectorNumElementAction(const unsigned Opcode, 346fe6060f1SDimitry Andric const unsigned TypeIndex, 347fe6060f1SDimitry Andric const unsigned ElementSize, 348fe6060f1SDimitry Andric const SizeAndActionsVec &SizeAndActions) { 349fe6060f1SDimitry Andric const unsigned OpcodeIdx = Opcode - FirstOp; 350fe6060f1SDimitry Andric if (NumElements2Actions[OpcodeIdx].find(ElementSize) == 351fe6060f1SDimitry Andric NumElements2Actions[OpcodeIdx].end()) 352fe6060f1SDimitry Andric NumElements2Actions[OpcodeIdx][ElementSize] = {{}}; 353fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> &Actions = 354fe6060f1SDimitry Andric NumElements2Actions[OpcodeIdx].find(ElementSize)->second; 355fe6060f1SDimitry Andric setActions(TypeIndex, Actions, SizeAndActions); 356fe6060f1SDimitry Andric } 357fe6060f1SDimitry Andric 358fe6060f1SDimitry Andric /// A partial SizeAndActionsVec potentially doesn't cover all bit sizes, 359fe6060f1SDimitry Andric /// i.e. it's OK if it doesn't start from size 1. checkPartialSizeAndActionsVector(const SizeAndActionsVec & v)360fe6060f1SDimitry Andric static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) { 361fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 362fe6060f1SDimitry Andric #ifndef NDEBUG 363fe6060f1SDimitry Andric // The sizes should be in increasing order 364fe6060f1SDimitry Andric int prev_size = -1; 365fe6060f1SDimitry Andric for(auto SizeAndAction: v) { 366fe6060f1SDimitry Andric assert(SizeAndAction.first > prev_size); 367fe6060f1SDimitry Andric prev_size = SizeAndAction.first; 368fe6060f1SDimitry Andric } 369fe6060f1SDimitry Andric // - for every Widen action, there should be a larger bitsize that 370fe6060f1SDimitry Andric // can be legalized towards (e.g. Legal, Lower, Libcall or Custom 371fe6060f1SDimitry Andric // action). 372fe6060f1SDimitry Andric // - for every Narrow action, there should be a smaller bitsize that 373fe6060f1SDimitry Andric // can be legalized towards. 374fe6060f1SDimitry Andric int SmallestNarrowIdx = -1; 375fe6060f1SDimitry Andric int LargestWidenIdx = -1; 376fe6060f1SDimitry Andric int SmallestLegalizableToSameSizeIdx = -1; 377fe6060f1SDimitry Andric int LargestLegalizableToSameSizeIdx = -1; 378fe6060f1SDimitry Andric for(size_t i=0; i<v.size(); ++i) { 379fe6060f1SDimitry Andric switch (v[i].second) { 380fe6060f1SDimitry Andric case FewerElements: 381fe6060f1SDimitry Andric case NarrowScalar: 382fe6060f1SDimitry Andric if (SmallestNarrowIdx == -1) 383fe6060f1SDimitry Andric SmallestNarrowIdx = i; 384fe6060f1SDimitry Andric break; 385fe6060f1SDimitry Andric case WidenScalar: 386fe6060f1SDimitry Andric case MoreElements: 387fe6060f1SDimitry Andric LargestWidenIdx = i; 388fe6060f1SDimitry Andric break; 389fe6060f1SDimitry Andric case Unsupported: 390fe6060f1SDimitry Andric break; 391fe6060f1SDimitry Andric default: 392fe6060f1SDimitry Andric if (SmallestLegalizableToSameSizeIdx == -1) 393fe6060f1SDimitry Andric SmallestLegalizableToSameSizeIdx = i; 394fe6060f1SDimitry Andric LargestLegalizableToSameSizeIdx = i; 395fe6060f1SDimitry Andric } 396fe6060f1SDimitry Andric } 397fe6060f1SDimitry Andric if (SmallestNarrowIdx != -1) { 398fe6060f1SDimitry Andric assert(SmallestLegalizableToSameSizeIdx != -1); 399fe6060f1SDimitry Andric assert(SmallestNarrowIdx > SmallestLegalizableToSameSizeIdx); 400fe6060f1SDimitry Andric } 401fe6060f1SDimitry Andric if (LargestWidenIdx != -1) 402fe6060f1SDimitry Andric assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx); 403fe6060f1SDimitry Andric #endif 404fe6060f1SDimitry Andric } 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric /// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with 407fe6060f1SDimitry Andric /// from size 1. checkFullSizeAndActionsVector(const SizeAndActionsVec & v)408fe6060f1SDimitry Andric static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) { 409fe6060f1SDimitry Andric #ifndef NDEBUG 410fe6060f1SDimitry Andric // Data structure invariant: The first bit size must be size 1. 411fe6060f1SDimitry Andric assert(v.size() >= 1); 412fe6060f1SDimitry Andric assert(v[0].first == 1); 413fe6060f1SDimitry Andric checkPartialSizeAndActionsVector(v); 414fe6060f1SDimitry Andric #endif 415fe6060f1SDimitry Andric } 416fe6060f1SDimitry Andric 417fe6060f1SDimitry Andric /// Sets actions for all bit sizes on a particular generic opcode, type 418fe6060f1SDimitry Andric /// index and scalar or pointer type. setActions(unsigned TypeIndex,SmallVector<SizeAndActionsVec,1> & Actions,const SizeAndActionsVec & SizeAndActions)419fe6060f1SDimitry Andric void setActions(unsigned TypeIndex, 420fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> &Actions, 421fe6060f1SDimitry Andric const SizeAndActionsVec &SizeAndActions) { 422fe6060f1SDimitry Andric checkFullSizeAndActionsVector(SizeAndActions); 423fe6060f1SDimitry Andric if (Actions.size() <= TypeIndex) 424fe6060f1SDimitry Andric Actions.resize(TypeIndex + 1); 425fe6060f1SDimitry Andric Actions[TypeIndex] = SizeAndActions; 426fe6060f1SDimitry Andric } 427fe6060f1SDimitry Andric 428fe6060f1SDimitry Andric static SizeAndAction findAction(const SizeAndActionsVec &Vec, 429fe6060f1SDimitry Andric const uint32_t Size); 430fe6060f1SDimitry Andric 431fe6060f1SDimitry Andric /// Returns the next action needed to get the scalar or pointer type closer 432fe6060f1SDimitry Andric /// to being legal 433fe6060f1SDimitry Andric /// E.g. findLegalAction({G_REM, 13}) should return 434fe6060f1SDimitry Andric /// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will 435fe6060f1SDimitry Andric /// probably be called, which should return (Lower, 32). 436fe6060f1SDimitry Andric /// This is assuming the setScalarAction on G_REM was something like: 437fe6060f1SDimitry Andric /// setScalarAction(G_REM, 0, 438fe6060f1SDimitry Andric /// {{1, WidenScalar}, // bit sizes [ 1, 31[ 439fe6060f1SDimitry Andric /// {32, Lower}, // bit sizes [32, 33[ 440fe6060f1SDimitry Andric /// {33, NarrowScalar} // bit sizes [65, +inf[ 441fe6060f1SDimitry Andric /// }); 442fe6060f1SDimitry Andric std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT> 443fe6060f1SDimitry Andric findScalarLegalAction(const InstrAspect &Aspect) const; 444fe6060f1SDimitry Andric 445fe6060f1SDimitry Andric /// Returns the next action needed towards legalizing the vector type. 446fe6060f1SDimitry Andric std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT> 447fe6060f1SDimitry Andric findVectorLegalAction(const InstrAspect &Aspect) const; 448fe6060f1SDimitry Andric 449fe6060f1SDimitry Andric static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START; 450fe6060f1SDimitry Andric static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; 451fe6060f1SDimitry Andric 452fe6060f1SDimitry Andric // Data structures used temporarily during construction of legality data: 453fe6060f1SDimitry Andric using TypeMap = DenseMap<LLT, LegacyLegalizeActions::LegacyLegalizeAction>; 454fe6060f1SDimitry Andric SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1]; 455fe6060f1SDimitry Andric SmallVector<SizeChangeStrategy, 1> 456fe6060f1SDimitry Andric ScalarSizeChangeStrategies[LastOp - FirstOp + 1]; 457fe6060f1SDimitry Andric SmallVector<SizeChangeStrategy, 1> 458fe6060f1SDimitry Andric VectorElementSizeChangeStrategies[LastOp - FirstOp + 1]; 4591fd87a68SDimitry Andric bool TablesInitialized = false; 460fe6060f1SDimitry Andric 461fe6060f1SDimitry Andric // Data structures used by getAction: 462fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1]; 463fe6060f1SDimitry Andric SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1]; 464fe6060f1SDimitry Andric std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>> 465fe6060f1SDimitry Andric AddrSpace2PointerActions[LastOp - FirstOp + 1]; 466fe6060f1SDimitry Andric std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>> 467fe6060f1SDimitry Andric NumElements2Actions[LastOp - FirstOp + 1]; 468fe6060f1SDimitry Andric }; 469fe6060f1SDimitry Andric 470fe6060f1SDimitry Andric } // end namespace llvm 471fe6060f1SDimitry Andric 472349cc55cSDimitry Andric #endif // LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H 473