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