static LegalizeMutation oneMoreElement(unsigned TypeIdx) { return [=](const LegalityQuery &Query) { const LLT Ty = Query.Types[TypeIdx]; const LLT EltTy = Ty.getElementType(); return std::make_pair(TypeIdx, LLT::vector(Ty.getNumElements() + 1, EltTy)); }; }
static LegalityPredicate isSmallOddVector(unsigned TypeIdx) { return [=](const LegalityQuery &Query) { const LLT Ty = Query.Types[TypeIdx]; return Ty.isVector() && Ty.getNumElements() % 2 != 0 && Ty.getElementType().getSizeInBits() < 32; }; }
// Make sure the returned mutation makes sense for the match type. static bool mutationIsSane(const LegalizeRule &Rule, const LegalityQuery &Q, std::pair<unsigned, LLT> Mutation) { const unsigned TypeIdx = Mutation.first; const LLT OldTy = Q.Types[TypeIdx]; const LLT NewTy = Mutation.second; switch (Rule.getAction()) { case FewerElements: case MoreElements: { if (!OldTy.isVector()) return false; if (NewTy.isVector()) { if (Rule.getAction() == FewerElements) { // Make sure the element count really decreased. if (NewTy.getNumElements() >= OldTy.getNumElements()) return false; } else { // Make sure the element count really increased. if (NewTy.getNumElements() <= OldTy.getNumElements()) return false; } } // Make sure the element type didn't change. return NewTy.getScalarType() == OldTy.getElementType(); } case NarrowScalar: case WidenScalar: { if (OldTy.isVector()) { // Number of elements should not change. if (!NewTy.isVector() || OldTy.getNumElements() != NewTy.getNumElements()) return false; } else { // Both types must be vectors if (NewTy.isVector()) return false; } if (Rule.getAction() == NarrowScalar) { // Make sure the size really decreased. if (NewTy.getScalarSizeInBits() >= OldTy.getScalarSizeInBits()) return false; } else { // Make sure the size really increased. if (NewTy.getScalarSizeInBits() <= OldTy.getScalarSizeInBits()) return false; } return true; } default: return true; } }
static LegalizeMutation fewerEltsToSize64Vector(unsigned TypeIdx) { return [=](const LegalityQuery &Query) { const LLT Ty = Query.Types[TypeIdx]; const LLT EltTy = Ty.getElementType(); unsigned Size = Ty.getSizeInBits(); unsigned Pieces = (Size + 63) / 64; unsigned NewNumElts = (Ty.getNumElements() + 1) / Pieces; return std::make_pair(TypeIdx, LLT::scalarOrVector(NewNumElts, EltTy)); }; }
LegalizeMutation LegalizeMutations::moreElementsToNextPow2(unsigned TypeIdx, unsigned Min) { return [=](const LegalityQuery &Query) { const LLT VecTy = Query.Types[TypeIdx]; unsigned NewNumElements = std::max(1u << Log2_32_Ceil(VecTy.getNumElements()), Min); return std::make_pair(TypeIdx, LLT::vector(NewNumElements, VecTy.getElementType())); }; }
void MachineLegalizer::computeTables() { for (auto &Op : Actions) { LLT Ty = Op.first.second; if (!Ty.isVector()) continue; auto &Entry = MaxLegalVectorElts[std::make_pair(Op.first.first, Ty.getElementType())]; Entry = std::max(Entry, Ty.getNumElements()); } TablesInitialized = true; }
// FIXME: inefficient implementation for now. Without ComputeValueVTs we're // probably going to need specialized lookup structures for various types before // we have any hope of doing well with something like <13 x i3>. Even the common // cases should do better than what we have now. std::pair<MachineLegalizer::LegalizeAction, LLT> MachineLegalizer::getAction(const InstrAspect &Aspect) const { assert(TablesInitialized && "backend forgot to call computeTables"); // These *have* to be implemented for now, they're the fundamental basis of // how everything else is transformed. // FIXME: the long-term plan calls for expansion in terms of load/store (if // they're not legal). if (Aspect.Opcode == TargetOpcode::G_SEQUENCE || Aspect.Opcode == TargetOpcode::G_EXTRACT) return std::make_pair(Legal, Aspect.Type); LegalizeAction Action = findInActions(Aspect); if (Action != NotFound) return findLegalAction(Aspect, Action); unsigned Opcode = Aspect.Opcode; LLT Ty = Aspect.Type; if (!Ty.isVector()) { auto DefaultAction = DefaultActions.find(Aspect.Opcode); if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal) return std::make_pair(Legal, Ty); assert(DefaultAction->second == NarrowScalar && "unexpected default"); return findLegalAction(Aspect, NarrowScalar); } LLT EltTy = Ty.getElementType(); int NumElts = Ty.getNumElements(); auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy)); if (ScalarAction != ScalarInVectorActions.end() && ScalarAction->second != Legal) return findLegalAction(Aspect, ScalarAction->second); // The element type is legal in principle, but the number of elements is // wrong. auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy)); if (MaxLegalElts > NumElts) return findLegalAction(Aspect, MoreElements); if (MaxLegalElts == 0) { // Scalarize if there's no legal vector type, which is just a special case // of FewerElements. return std::make_pair(FewerElements, EltTy); } return findLegalAction(Aspect, FewerElements); }
void LegalizerInfo::computeTables() { for (unsigned Opcode = 0; Opcode <= LastOp - FirstOp; ++Opcode) { for (unsigned Idx = 0; Idx != Actions[Opcode].size(); ++Idx) { for (auto &Action : Actions[Opcode][Idx]) { LLT Ty = Action.first; if (!Ty.isVector()) continue; auto &Entry = MaxLegalVectorElts[std::make_pair(Opcode + FirstOp, Ty.getElementType())]; Entry = std::max(Entry, Ty.getNumElements()); } } } TablesInitialized = true; }
// FIXME: inefficient implementation for now. Without ComputeValueVTs we're // probably going to need specialized lookup structures for various types before // we have any hope of doing well with something like <13 x i3>. Even the common // cases should do better than what we have now. std::pair<LegalizerInfo::LegalizeAction, LLT> LegalizerInfo::getAction(const InstrAspect &Aspect) const { assert(TablesInitialized && "backend forgot to call computeTables"); // These *have* to be implemented for now, they're the fundamental basis of // how everything else is transformed. // FIXME: the long-term plan calls for expansion in terms of load/store (if // they're not legal). if (Aspect.Opcode == TargetOpcode::G_MERGE_VALUES || Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES) return std::make_pair(Legal, Aspect.Type); LLT Ty = Aspect.Type; LegalizeAction Action = findInActions(Aspect); // LegalizerHelper is not able to handle non-power-of-2 types right now, so do // not try to legalize them unless they are marked as Legal or Custom. // FIXME: This is a temporary hack until the general non-power-of-2 // legalization works. if (!isPowerOf2_64(Ty.getSizeInBits()) && !(Action == Legal || Action == Custom)) return std::make_pair(Unsupported, LLT()); if (Action != NotFound) return findLegalAction(Aspect, Action); unsigned Opcode = Aspect.Opcode; if (!Ty.isVector()) { auto DefaultAction = DefaultActions.find(Aspect.Opcode); if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal) return std::make_pair(Legal, Ty); if (DefaultAction != DefaultActions.end() && DefaultAction->second == Lower) return std::make_pair(Lower, Ty); if (DefaultAction == DefaultActions.end() || DefaultAction->second != NarrowScalar) return std::make_pair(Unsupported, LLT()); return findLegalAction(Aspect, NarrowScalar); } LLT EltTy = Ty.getElementType(); int NumElts = Ty.getNumElements(); auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy)); if (ScalarAction != ScalarInVectorActions.end() && ScalarAction->second != Legal) return findLegalAction(Aspect, ScalarAction->second); // The element type is legal in principle, but the number of elements is // wrong. auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy)); if (MaxLegalElts > NumElts) return findLegalAction(Aspect, MoreElements); if (MaxLegalElts == 0) { // Scalarize if there's no legal vector type, which is just a special case // of FewerElements. return std::make_pair(FewerElements, EltTy); } return findLegalAction(Aspect, FewerElements); }
void LegalizerInfo::computeTables() { assert(TablesInitialized == false); for (unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) { const unsigned Opcode = FirstOp + OpcodeIdx; for (unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size(); ++TypeIdx) { // 0. Collect information specified through the setAction API, i.e. // for specific bit sizes. // For scalar types: SizeAndActionsVec ScalarSpecifiedActions; // For pointer types: std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions; // For vector types: std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions; for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) { const LLT Type = LLT2Action.first; const LegalizeAction Action = LLT2Action.second; auto SizeAction = std::make_pair(Type.getSizeInBits(), Action); if (Type.isPointer()) AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back( SizeAction); else if (Type.isVector()) ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()] .push_back(SizeAction); else ScalarSpecifiedActions.push_back(SizeAction); } // 1. Handle scalar types { // Decide how to handle bit sizes for which no explicit specification // was given. SizeChangeStrategy S = &unsupportedForDifferentSizes; if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() && ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx]; std::sort(ScalarSpecifiedActions.begin(), ScalarSpecifiedActions.end()); checkPartialSizeAndActionsVector(ScalarSpecifiedActions); setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions)); } // 2. Handle pointer types for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) { std::sort(PointerSpecifiedActions.second.begin(), PointerSpecifiedActions.second.end()); checkPartialSizeAndActionsVector(PointerSpecifiedActions.second); // For pointer types, we assume that there isn't a meaningfull way // to change the number of bits used in the pointer. setPointerAction( Opcode, TypeIdx, PointerSpecifiedActions.first, unsupportedForDifferentSizes(PointerSpecifiedActions.second)); } // 3. Handle vector types SizeAndActionsVec ElementSizesSeen; for (auto VectorSpecifiedActions : ElemSize2SpecifiedActions) { std::sort(VectorSpecifiedActions.second.begin(), VectorSpecifiedActions.second.end()); const uint16_t ElementSize = VectorSpecifiedActions.first; ElementSizesSeen.push_back({ElementSize, Legal}); checkPartialSizeAndActionsVector(VectorSpecifiedActions.second); // For vector types, we assume that the best way to adapt the number // of elements is to the next larger number of elements type for which // the vector type is legal, unless there is no such type. In that case, // legalize towards a vector type with a smaller number of elements. SizeAndActionsVec NumElementsActions; for (SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) { assert(BitsizeAndAction.first % ElementSize == 0); const uint16_t NumElements = BitsizeAndAction.first / ElementSize; NumElementsActions.push_back({NumElements, BitsizeAndAction.second}); } setVectorNumElementAction( Opcode, TypeIdx, ElementSize, moreToWiderTypesAndLessToWidest(NumElementsActions)); } std::sort(ElementSizesSeen.begin(), ElementSizesSeen.end()); SizeChangeStrategy VectorElementSizeChangeStrategy = &unsupportedForDifferentSizes; if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() && VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) VectorElementSizeChangeStrategy = VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx]; setScalarInVectorAction( Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen)); } } TablesInitialized = true; }