1fe6060f1SDimitry Andric //===- lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp - Legalizer ---------===// 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 // 9fe6060f1SDimitry Andric // Implement an interface to specify and query how an illegal operation on a 10fe6060f1SDimitry Andric // given type should be expanded. 11fe6060f1SDimitry Andric // 12fe6060f1SDimitry Andric // Issues to be resolved: 13fe6060f1SDimitry Andric // + Make it fast. 14fe6060f1SDimitry Andric // + Support weird types like i3, <7 x i3>, ... 15fe6060f1SDimitry Andric // + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...) 16fe6060f1SDimitry Andric // 17fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 18fe6060f1SDimitry Andric 19fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h" 20fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 21fe6060f1SDimitry Andric #include <map> 22fe6060f1SDimitry Andric 23fe6060f1SDimitry Andric using namespace llvm; 24fe6060f1SDimitry Andric using namespace LegacyLegalizeActions; 25fe6060f1SDimitry Andric 26fe6060f1SDimitry Andric #define DEBUG_TYPE "legalizer-info" 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, LegacyLegalizeAction Action) { 29fe6060f1SDimitry Andric switch (Action) { 30fe6060f1SDimitry Andric case Legal: 31fe6060f1SDimitry Andric OS << "Legal"; 32fe6060f1SDimitry Andric break; 33fe6060f1SDimitry Andric case NarrowScalar: 34fe6060f1SDimitry Andric OS << "NarrowScalar"; 35fe6060f1SDimitry Andric break; 36fe6060f1SDimitry Andric case WidenScalar: 37fe6060f1SDimitry Andric OS << "WidenScalar"; 38fe6060f1SDimitry Andric break; 39fe6060f1SDimitry Andric case FewerElements: 40fe6060f1SDimitry Andric OS << "FewerElements"; 41fe6060f1SDimitry Andric break; 42fe6060f1SDimitry Andric case MoreElements: 43fe6060f1SDimitry Andric OS << "MoreElements"; 44fe6060f1SDimitry Andric break; 45fe6060f1SDimitry Andric case Bitcast: 46fe6060f1SDimitry Andric OS << "Bitcast"; 47fe6060f1SDimitry Andric break; 48fe6060f1SDimitry Andric case Lower: 49fe6060f1SDimitry Andric OS << "Lower"; 50fe6060f1SDimitry Andric break; 51fe6060f1SDimitry Andric case Libcall: 52fe6060f1SDimitry Andric OS << "Libcall"; 53fe6060f1SDimitry Andric break; 54fe6060f1SDimitry Andric case Custom: 55fe6060f1SDimitry Andric OS << "Custom"; 56fe6060f1SDimitry Andric break; 57fe6060f1SDimitry Andric case Unsupported: 58fe6060f1SDimitry Andric OS << "Unsupported"; 59fe6060f1SDimitry Andric break; 60fe6060f1SDimitry Andric case NotFound: 61fe6060f1SDimitry Andric OS << "NotFound"; 62fe6060f1SDimitry Andric break; 63fe6060f1SDimitry Andric } 64fe6060f1SDimitry Andric return OS; 65fe6060f1SDimitry Andric } 66fe6060f1SDimitry Andric 671fd87a68SDimitry Andric LegacyLegalizerInfo::LegacyLegalizerInfo() { 68fe6060f1SDimitry Andric // Set defaults. 69fe6060f1SDimitry Andric // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the 70fe6060f1SDimitry Andric // fundamental load/store Jakob proposed. Once loads & stores are supported. 71fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}}); 72fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}}); 73fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}}); 74fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}}); 75fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}}); 76fe6060f1SDimitry Andric 77fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}}); 78fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}}); 79fe6060f1SDimitry Andric 80fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 81fe6060f1SDimitry Andric TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall); 82fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 83fe6060f1SDimitry Andric TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest); 84fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 85fe6060f1SDimitry Andric TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest); 86fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 87fe6060f1SDimitry Andric TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall); 88fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 89fe6060f1SDimitry Andric TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall); 90fe6060f1SDimitry Andric 91fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 92fe6060f1SDimitry Andric TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise); 93fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 94fe6060f1SDimitry Andric TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall); 95fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 96fe6060f1SDimitry Andric TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall); 97fe6060f1SDimitry Andric setLegalizeScalarToDifferentSizeStrategy( 98fe6060f1SDimitry Andric TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall); 99fe6060f1SDimitry Andric setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}}); 100fe6060f1SDimitry Andric } 101fe6060f1SDimitry Andric 102fe6060f1SDimitry Andric void LegacyLegalizerInfo::computeTables() { 103fe6060f1SDimitry Andric assert(TablesInitialized == false); 104fe6060f1SDimitry Andric 105fe6060f1SDimitry Andric for (unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) { 106fe6060f1SDimitry Andric const unsigned Opcode = FirstOp + OpcodeIdx; 107fe6060f1SDimitry Andric for (unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size(); 108fe6060f1SDimitry Andric ++TypeIdx) { 109fe6060f1SDimitry Andric // 0. Collect information specified through the setAction API, i.e. 110fe6060f1SDimitry Andric // for specific bit sizes. 111fe6060f1SDimitry Andric // For scalar types: 112fe6060f1SDimitry Andric SizeAndActionsVec ScalarSpecifiedActions; 113fe6060f1SDimitry Andric // For pointer types: 114fe6060f1SDimitry Andric std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions; 115fe6060f1SDimitry Andric // For vector types: 116fe6060f1SDimitry Andric std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions; 117fe6060f1SDimitry Andric for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) { 118fe6060f1SDimitry Andric const LLT Type = LLT2Action.first; 119fe6060f1SDimitry Andric const LegacyLegalizeAction Action = LLT2Action.second; 120fe6060f1SDimitry Andric 121fe6060f1SDimitry Andric auto SizeAction = std::make_pair(Type.getSizeInBits(), Action); 122fe6060f1SDimitry Andric if (Type.isPointer()) 123fe6060f1SDimitry Andric AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back( 124fe6060f1SDimitry Andric SizeAction); 125fe6060f1SDimitry Andric else if (Type.isVector()) 126fe6060f1SDimitry Andric ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()] 127fe6060f1SDimitry Andric .push_back(SizeAction); 128fe6060f1SDimitry Andric else 129fe6060f1SDimitry Andric ScalarSpecifiedActions.push_back(SizeAction); 130fe6060f1SDimitry Andric } 131fe6060f1SDimitry Andric 132fe6060f1SDimitry Andric // 1. Handle scalar types 133fe6060f1SDimitry Andric { 134fe6060f1SDimitry Andric // Decide how to handle bit sizes for which no explicit specification 135fe6060f1SDimitry Andric // was given. 136fe6060f1SDimitry Andric SizeChangeStrategy S = &unsupportedForDifferentSizes; 137fe6060f1SDimitry Andric if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() && 138fe6060f1SDimitry Andric ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) 139fe6060f1SDimitry Andric S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx]; 140fe6060f1SDimitry Andric llvm::sort(ScalarSpecifiedActions); 141fe6060f1SDimitry Andric checkPartialSizeAndActionsVector(ScalarSpecifiedActions); 142fe6060f1SDimitry Andric setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions)); 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric // 2. Handle pointer types 146fe6060f1SDimitry Andric for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) { 147fe6060f1SDimitry Andric llvm::sort(PointerSpecifiedActions.second); 148fe6060f1SDimitry Andric checkPartialSizeAndActionsVector(PointerSpecifiedActions.second); 149fe6060f1SDimitry Andric // For pointer types, we assume that there isn't a meaningfull way 150fe6060f1SDimitry Andric // to change the number of bits used in the pointer. 151fe6060f1SDimitry Andric setPointerAction( 152fe6060f1SDimitry Andric Opcode, TypeIdx, PointerSpecifiedActions.first, 153fe6060f1SDimitry Andric unsupportedForDifferentSizes(PointerSpecifiedActions.second)); 154fe6060f1SDimitry Andric } 155fe6060f1SDimitry Andric 156fe6060f1SDimitry Andric // 3. Handle vector types 157fe6060f1SDimitry Andric SizeAndActionsVec ElementSizesSeen; 158fe6060f1SDimitry Andric for (auto VectorSpecifiedActions : ElemSize2SpecifiedActions) { 159fe6060f1SDimitry Andric llvm::sort(VectorSpecifiedActions.second); 160fe6060f1SDimitry Andric const uint16_t ElementSize = VectorSpecifiedActions.first; 161fe6060f1SDimitry Andric ElementSizesSeen.push_back({ElementSize, Legal}); 162fe6060f1SDimitry Andric checkPartialSizeAndActionsVector(VectorSpecifiedActions.second); 163fe6060f1SDimitry Andric // For vector types, we assume that the best way to adapt the number 164fe6060f1SDimitry Andric // of elements is to the next larger number of elements type for which 165fe6060f1SDimitry Andric // the vector type is legal, unless there is no such type. In that case, 166fe6060f1SDimitry Andric // legalize towards a vector type with a smaller number of elements. 167fe6060f1SDimitry Andric SizeAndActionsVec NumElementsActions; 168fe6060f1SDimitry Andric for (SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) { 169fe6060f1SDimitry Andric assert(BitsizeAndAction.first % ElementSize == 0); 170fe6060f1SDimitry Andric const uint16_t NumElements = BitsizeAndAction.first / ElementSize; 171fe6060f1SDimitry Andric NumElementsActions.push_back({NumElements, BitsizeAndAction.second}); 172fe6060f1SDimitry Andric } 173fe6060f1SDimitry Andric setVectorNumElementAction( 174fe6060f1SDimitry Andric Opcode, TypeIdx, ElementSize, 175fe6060f1SDimitry Andric moreToWiderTypesAndLessToWidest(NumElementsActions)); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric llvm::sort(ElementSizesSeen); 178fe6060f1SDimitry Andric SizeChangeStrategy VectorElementSizeChangeStrategy = 179fe6060f1SDimitry Andric &unsupportedForDifferentSizes; 180fe6060f1SDimitry Andric if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() && 181fe6060f1SDimitry Andric VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) 182fe6060f1SDimitry Andric VectorElementSizeChangeStrategy = 183fe6060f1SDimitry Andric VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx]; 184fe6060f1SDimitry Andric setScalarInVectorAction( 185fe6060f1SDimitry Andric Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen)); 186fe6060f1SDimitry Andric } 187fe6060f1SDimitry Andric } 188fe6060f1SDimitry Andric 189fe6060f1SDimitry Andric TablesInitialized = true; 190fe6060f1SDimitry Andric } 191fe6060f1SDimitry Andric 192fe6060f1SDimitry Andric // FIXME: inefficient implementation for now. Without ComputeValueVTs we're 193fe6060f1SDimitry Andric // probably going to need specialized lookup structures for various types before 194fe6060f1SDimitry Andric // we have any hope of doing well with something like <13 x i3>. Even the common 195fe6060f1SDimitry Andric // cases should do better than what we have now. 196fe6060f1SDimitry Andric std::pair<LegacyLegalizeAction, LLT> 197fe6060f1SDimitry Andric LegacyLegalizerInfo::getAspectAction(const InstrAspect &Aspect) const { 198fe6060f1SDimitry Andric assert(TablesInitialized && "backend forgot to call computeTables"); 199fe6060f1SDimitry Andric // These *have* to be implemented for now, they're the fundamental basis of 200fe6060f1SDimitry Andric // how everything else is transformed. 201fe6060f1SDimitry Andric if (Aspect.Type.isScalar() || Aspect.Type.isPointer()) 202fe6060f1SDimitry Andric return findScalarLegalAction(Aspect); 203fe6060f1SDimitry Andric assert(Aspect.Type.isVector()); 204fe6060f1SDimitry Andric return findVectorLegalAction(Aspect); 205fe6060f1SDimitry Andric } 206fe6060f1SDimitry Andric 207fe6060f1SDimitry Andric LegacyLegalizerInfo::SizeAndActionsVec 208fe6060f1SDimitry Andric LegacyLegalizerInfo::increaseToLargerTypesAndDecreaseToLargest( 209fe6060f1SDimitry Andric const SizeAndActionsVec &v, LegacyLegalizeAction IncreaseAction, 210fe6060f1SDimitry Andric LegacyLegalizeAction DecreaseAction) { 211fe6060f1SDimitry Andric SizeAndActionsVec result; 212fe6060f1SDimitry Andric unsigned LargestSizeSoFar = 0; 213fe6060f1SDimitry Andric if (v.size() >= 1 && v[0].first != 1) 214fe6060f1SDimitry Andric result.push_back({1, IncreaseAction}); 215fe6060f1SDimitry Andric for (size_t i = 0; i < v.size(); ++i) { 216fe6060f1SDimitry Andric result.push_back(v[i]); 217fe6060f1SDimitry Andric LargestSizeSoFar = v[i].first; 218fe6060f1SDimitry Andric if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) { 219fe6060f1SDimitry Andric result.push_back({LargestSizeSoFar + 1, IncreaseAction}); 220fe6060f1SDimitry Andric LargestSizeSoFar = v[i].first + 1; 221fe6060f1SDimitry Andric } 222fe6060f1SDimitry Andric } 223fe6060f1SDimitry Andric result.push_back({LargestSizeSoFar + 1, DecreaseAction}); 224fe6060f1SDimitry Andric return result; 225fe6060f1SDimitry Andric } 226fe6060f1SDimitry Andric 227fe6060f1SDimitry Andric LegacyLegalizerInfo::SizeAndActionsVec 228fe6060f1SDimitry Andric LegacyLegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest( 229fe6060f1SDimitry Andric const SizeAndActionsVec &v, LegacyLegalizeAction DecreaseAction, 230fe6060f1SDimitry Andric LegacyLegalizeAction IncreaseAction) { 231fe6060f1SDimitry Andric SizeAndActionsVec result; 232fe6060f1SDimitry Andric if (v.size() == 0 || v[0].first != 1) 233fe6060f1SDimitry Andric result.push_back({1, IncreaseAction}); 234fe6060f1SDimitry Andric for (size_t i = 0; i < v.size(); ++i) { 235fe6060f1SDimitry Andric result.push_back(v[i]); 236fe6060f1SDimitry Andric if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) { 237fe6060f1SDimitry Andric result.push_back({v[i].first + 1, DecreaseAction}); 238fe6060f1SDimitry Andric } 239fe6060f1SDimitry Andric } 240fe6060f1SDimitry Andric return result; 241fe6060f1SDimitry Andric } 242fe6060f1SDimitry Andric 243fe6060f1SDimitry Andric LegacyLegalizerInfo::SizeAndAction 244fe6060f1SDimitry Andric LegacyLegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) { 245fe6060f1SDimitry Andric assert(Size >= 1); 246fe6060f1SDimitry Andric // Find the last element in Vec that has a bitsize equal to or smaller than 247fe6060f1SDimitry Andric // the requested bit size. 248fe6060f1SDimitry Andric // That is the element just before the first element that is bigger than Size. 249fe6060f1SDimitry Andric auto It = partition_point( 250fe6060f1SDimitry Andric Vec, [=](const SizeAndAction &A) { return A.first <= Size; }); 251fe6060f1SDimitry Andric assert(It != Vec.begin() && "Does Vec not start with size 1?"); 252fe6060f1SDimitry Andric int VecIdx = It - Vec.begin() - 1; 253fe6060f1SDimitry Andric 254fe6060f1SDimitry Andric LegacyLegalizeAction Action = Vec[VecIdx].second; 255fe6060f1SDimitry Andric switch (Action) { 256fe6060f1SDimitry Andric case Legal: 257fe6060f1SDimitry Andric case Bitcast: 258fe6060f1SDimitry Andric case Lower: 259fe6060f1SDimitry Andric case Libcall: 260fe6060f1SDimitry Andric case Custom: 261fe6060f1SDimitry Andric return {Size, Action}; 262fe6060f1SDimitry Andric case FewerElements: 263fe6060f1SDimitry Andric // FIXME: is this special case still needed and correct? 264fe6060f1SDimitry Andric // Special case for scalarization: 265fe6060f1SDimitry Andric if (Vec == SizeAndActionsVec({{1, FewerElements}})) 266fe6060f1SDimitry Andric return {1, FewerElements}; 267*bdd1243dSDimitry Andric [[fallthrough]]; 268fe6060f1SDimitry Andric case NarrowScalar: { 269fe6060f1SDimitry Andric // The following needs to be a loop, as for now, we do allow needing to 270fe6060f1SDimitry Andric // go over "Unsupported" bit sizes before finding a legalizable bit size. 271fe6060f1SDimitry Andric // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8, 272fe6060f1SDimitry Andric // we need to iterate over s9, and then to s32 to return (s32, Legal). 273fe6060f1SDimitry Andric // If we want to get rid of the below loop, we should have stronger asserts 274fe6060f1SDimitry Andric // when building the SizeAndActionsVecs, probably not allowing 275fe6060f1SDimitry Andric // "Unsupported" unless at the ends of the vector. 276fe6060f1SDimitry Andric for (int i = VecIdx - 1; i >= 0; --i) 277fe6060f1SDimitry Andric if (!needsLegalizingToDifferentSize(Vec[i].second) && 278fe6060f1SDimitry Andric Vec[i].second != Unsupported) 279fe6060f1SDimitry Andric return {Vec[i].first, Action}; 280fe6060f1SDimitry Andric llvm_unreachable(""); 281fe6060f1SDimitry Andric } 282fe6060f1SDimitry Andric case WidenScalar: 283fe6060f1SDimitry Andric case MoreElements: { 284fe6060f1SDimitry Andric // See above, the following needs to be a loop, at least for now. 285fe6060f1SDimitry Andric for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i) 286fe6060f1SDimitry Andric if (!needsLegalizingToDifferentSize(Vec[i].second) && 287fe6060f1SDimitry Andric Vec[i].second != Unsupported) 288fe6060f1SDimitry Andric return {Vec[i].first, Action}; 289fe6060f1SDimitry Andric llvm_unreachable(""); 290fe6060f1SDimitry Andric } 291fe6060f1SDimitry Andric case Unsupported: 292fe6060f1SDimitry Andric return {Size, Unsupported}; 293fe6060f1SDimitry Andric case NotFound: 294fe6060f1SDimitry Andric llvm_unreachable("NotFound"); 295fe6060f1SDimitry Andric } 296fe6060f1SDimitry Andric llvm_unreachable("Action has an unknown enum value"); 297fe6060f1SDimitry Andric } 298fe6060f1SDimitry Andric 299fe6060f1SDimitry Andric std::pair<LegacyLegalizeAction, LLT> 300fe6060f1SDimitry Andric LegacyLegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const { 301fe6060f1SDimitry Andric assert(Aspect.Type.isScalar() || Aspect.Type.isPointer()); 302fe6060f1SDimitry Andric if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) 303fe6060f1SDimitry Andric return {NotFound, LLT()}; 304fe6060f1SDimitry Andric const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode); 305fe6060f1SDimitry Andric if (Aspect.Type.isPointer() && 306fe6060f1SDimitry Andric AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) == 307fe6060f1SDimitry Andric AddrSpace2PointerActions[OpcodeIdx].end()) { 308fe6060f1SDimitry Andric return {NotFound, LLT()}; 309fe6060f1SDimitry Andric } 310fe6060f1SDimitry Andric const SmallVector<SizeAndActionsVec, 1> &Actions = 311fe6060f1SDimitry Andric Aspect.Type.isPointer() 312fe6060f1SDimitry Andric ? AddrSpace2PointerActions[OpcodeIdx] 313fe6060f1SDimitry Andric .find(Aspect.Type.getAddressSpace()) 314fe6060f1SDimitry Andric ->second 315fe6060f1SDimitry Andric : ScalarActions[OpcodeIdx]; 316fe6060f1SDimitry Andric if (Aspect.Idx >= Actions.size()) 317fe6060f1SDimitry Andric return {NotFound, LLT()}; 318fe6060f1SDimitry Andric const SizeAndActionsVec &Vec = Actions[Aspect.Idx]; 319fe6060f1SDimitry Andric // FIXME: speed up this search, e.g. by using a results cache for repeated 320fe6060f1SDimitry Andric // queries? 321fe6060f1SDimitry Andric auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits()); 322fe6060f1SDimitry Andric return {SizeAndAction.second, 323fe6060f1SDimitry Andric Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first) 324fe6060f1SDimitry Andric : LLT::pointer(Aspect.Type.getAddressSpace(), 325fe6060f1SDimitry Andric SizeAndAction.first)}; 326fe6060f1SDimitry Andric } 327fe6060f1SDimitry Andric 328fe6060f1SDimitry Andric std::pair<LegacyLegalizeAction, LLT> 329fe6060f1SDimitry Andric LegacyLegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const { 330fe6060f1SDimitry Andric assert(Aspect.Type.isVector()); 331fe6060f1SDimitry Andric // First legalize the vector element size, then legalize the number of 332fe6060f1SDimitry Andric // lanes in the vector. 333fe6060f1SDimitry Andric if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) 334fe6060f1SDimitry Andric return {NotFound, Aspect.Type}; 335fe6060f1SDimitry Andric const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode); 336fe6060f1SDimitry Andric const unsigned TypeIdx = Aspect.Idx; 337fe6060f1SDimitry Andric if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size()) 338fe6060f1SDimitry Andric return {NotFound, Aspect.Type}; 339fe6060f1SDimitry Andric const SizeAndActionsVec &ElemSizeVec = 340fe6060f1SDimitry Andric ScalarInVectorActions[OpcodeIdx][TypeIdx]; 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric LLT IntermediateType; 343fe6060f1SDimitry Andric auto ElementSizeAndAction = 344fe6060f1SDimitry Andric findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits()); 345fe6060f1SDimitry Andric IntermediateType = LLT::fixed_vector(Aspect.Type.getNumElements(), 346fe6060f1SDimitry Andric ElementSizeAndAction.first); 347fe6060f1SDimitry Andric if (ElementSizeAndAction.second != Legal) 348fe6060f1SDimitry Andric return {ElementSizeAndAction.second, IntermediateType}; 349fe6060f1SDimitry Andric 350fe6060f1SDimitry Andric auto i = NumElements2Actions[OpcodeIdx].find( 351fe6060f1SDimitry Andric IntermediateType.getScalarSizeInBits()); 352fe6060f1SDimitry Andric if (i == NumElements2Actions[OpcodeIdx].end()) { 353fe6060f1SDimitry Andric return {NotFound, IntermediateType}; 354fe6060f1SDimitry Andric } 355fe6060f1SDimitry Andric const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx]; 356fe6060f1SDimitry Andric auto NumElementsAndAction = 357fe6060f1SDimitry Andric findAction(NumElementsVec, IntermediateType.getNumElements()); 358fe6060f1SDimitry Andric return {NumElementsAndAction.second, 359fe6060f1SDimitry Andric LLT::fixed_vector(NumElementsAndAction.first, 360fe6060f1SDimitry Andric IntermediateType.getScalarSizeInBits())}; 361fe6060f1SDimitry Andric } 362fe6060f1SDimitry Andric 363fe6060f1SDimitry Andric unsigned LegacyLegalizerInfo::getOpcodeIdxForOpcode(unsigned Opcode) const { 364fe6060f1SDimitry Andric assert(Opcode >= FirstOp && Opcode <= LastOp && "Unsupported opcode"); 365fe6060f1SDimitry Andric return Opcode - FirstOp; 366fe6060f1SDimitry Andric } 367fe6060f1SDimitry Andric 368fe6060f1SDimitry Andric 369fe6060f1SDimitry Andric LegacyLegalizeActionStep 370fe6060f1SDimitry Andric LegacyLegalizerInfo::getAction(const LegalityQuery &Query) const { 371fe6060f1SDimitry Andric for (unsigned i = 0; i < Query.Types.size(); ++i) { 372fe6060f1SDimitry Andric auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]}); 373fe6060f1SDimitry Andric if (Action.first != Legal) { 374fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Action=" 375fe6060f1SDimitry Andric << Action.first << ", " << Action.second << "\n"); 376fe6060f1SDimitry Andric return {Action.first, i, Action.second}; 377fe6060f1SDimitry Andric } else 378fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Legal\n"); 379fe6060f1SDimitry Andric } 380fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << ".. (legacy) Legal\n"); 381fe6060f1SDimitry Andric return {Legal, 0, LLT{}}; 382fe6060f1SDimitry Andric } 383fe6060f1SDimitry Andric 384