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