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