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