diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h @@ -0,0 +1,479 @@ +//===- llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// Interface for Targets to specify which operations they can successfully +/// select and how the others should be expanded most efficiently. +/// This implementation has been deprecated for a long time but it still in use +/// in a few places. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H +#define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/TargetOpcodes.h" +#include "llvm/Support/LowLevelTypeImpl.h" +#include + +namespace llvm { +struct LegalityQuery; + +namespace LegacyLegalizeActions { +enum LegacyLegalizeAction : std::uint8_t { + /// The operation is expected to be selectable directly by the target, and + /// no transformation is necessary. + Legal, + + /// The operation should be synthesized from multiple instructions acting on + /// a narrower scalar base-type. For example a 64-bit add might be + /// implemented in terms of 32-bit add-with-carry. + NarrowScalar, + + /// The operation should be implemented in terms of a wider scalar + /// base-type. For example a <2 x s8> add could be implemented as a <2 + /// x s32> add (ignoring the high bits). + WidenScalar, + + /// The (vector) operation should be implemented by splitting it into + /// sub-vectors where the operation is legal. For example a <8 x s64> add + /// might be implemented as 4 separate <2 x s64> adds. + FewerElements, + + /// The (vector) operation should be implemented by widening the input + /// vector and ignoring the lanes added by doing so. For example <2 x i8> is + /// rarely legal, but you might perform an <8 x i8> and then only look at + /// the first two results. + MoreElements, + + /// Perform the operation on a different, but equivalently sized type. + Bitcast, + + /// The operation itself must be expressed in terms of simpler actions on + /// this target. E.g. a SREM replaced by an SDIV and subtraction. + Lower, + + /// The operation should be implemented as a call to some kind of runtime + /// support library. For example this usually happens on machines that don't + /// support floating-point operations natively. + Libcall, + + /// The target wants to do something special with this combination of + /// operand and type. A callback will be issued when it is needed. + Custom, + + /// This operation is completely unsupported on the target. A programming + /// error has occurred. + Unsupported, + + /// Sentinel value for when no action was found in the specified table. + NotFound, +}; +} // end namespace LegacyLegalizeActions + +/// Legalization is decided based on an instruction's opcode, which type slot +/// we're considering, and what the existing type is. These aspects are gathered +/// together for convenience in the InstrAspect class. +struct InstrAspect { + unsigned Opcode; + unsigned Idx = 0; + LLT Type; + + InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {} + InstrAspect(unsigned Opcode, unsigned Idx, LLT Type) + : Opcode(Opcode), Idx(Idx), Type(Type) {} + + bool operator==(const InstrAspect &RHS) const { + return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type; + } +}; + +/// The result of a query. It either indicates a final answer of Legal or +/// Unsupported or describes an action that must be taken to make an operation +/// more legal. +struct LegacyLegalizeActionStep { + /// The action to take or the final answer. + LegacyLegalizeActions::LegacyLegalizeAction Action; + /// If describing an action, the type index to change. Otherwise zero. + unsigned TypeIdx; + /// If describing an action, the new type for TypeIdx. Otherwise LLT{}. + LLT NewType; + + LegacyLegalizeActionStep(LegacyLegalizeActions::LegacyLegalizeAction Action, + unsigned TypeIdx, const LLT NewType) + : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {} + + bool operator==(const LegacyLegalizeActionStep &RHS) const { + return std::tie(Action, TypeIdx, NewType) == + std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType); + } +}; + + +class LegacyLegalizerInfo { +public: + using SizeAndAction = + std::pair; + using SizeAndActionsVec = std::vector; + using SizeChangeStrategy = + std::function; + + LegacyLegalizerInfo(); + + static bool needsLegalizingToDifferentSize( + const LegacyLegalizeActions::LegacyLegalizeAction Action) { + using namespace LegacyLegalizeActions; + switch (Action) { + case NarrowScalar: + case WidenScalar: + case FewerElements: + case MoreElements: + case Unsupported: + return true; + default: + return false; + } + } + + /// Compute any ancillary tables needed to quickly decide how an operation + /// should be handled. This must be called after all "set*Action"methods but + /// before any query is made or incorrect results may be returned. + void computeTables(); + + /// More friendly way to set an action for common types that have an LLT + /// representation. + /// The LegacyLegalizeAction must be one for which + /// NeedsLegalizingToDifferentSize returns false. + void setAction(const InstrAspect &Aspect, + LegacyLegalizeActions::LegacyLegalizeAction Action) { + assert(!needsLegalizingToDifferentSize(Action)); + TablesInitialized = false; + const unsigned OpcodeIdx = Aspect.Opcode - FirstOp; + if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx) + SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1); + SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action; + } + + /// The setAction calls record the non-size-changing legalization actions + /// to take on specificly-sized types. The SizeChangeStrategy defines what + /// to do when the size of the type needs to be changed to reach a legally + /// sized type (i.e., one that was defined through a setAction call). + /// e.g. + /// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal); + /// setLegalizeScalarToDifferentSizeStrategy( + /// G_ADD, 0, widenToLargerTypesAndNarrowToLargest); + /// will end up defining getAction({G_ADD, 0, T}) to return the following + /// actions for different scalar types T: + /// LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)} + /// LLT::scalar(32): {Legal, 0, LLT::scalar(32)} + /// LLT::scalar(33)..: {NarrowScalar, 0, LLT::scalar(32)} + /// + /// If no SizeChangeAction gets defined, through this function, + /// the default is unsupportedForDifferentSizes. + void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode, + const unsigned TypeIdx, + SizeChangeStrategy S) { + const unsigned OpcodeIdx = Opcode - FirstOp; + if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx) + ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1); + ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S; + } + + /// See also setLegalizeScalarToDifferentSizeStrategy. + /// This function allows to set the SizeChangeStrategy for vector elements. + void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode, + const unsigned TypeIdx, + SizeChangeStrategy S) { + const unsigned OpcodeIdx = Opcode - FirstOp; + if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx) + VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1); + VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S; + } + + /// A SizeChangeStrategy for the common case where legalization for a + /// particular operation consists of only supporting a specific set of type + /// sizes. E.g. + /// setAction ({G_DIV, 0, LLT::scalar(32)}, Legal); + /// setAction ({G_DIV, 0, LLT::scalar(64)}, Legal); + /// setLegalizeScalarToDifferentSizeStrategy( + /// G_DIV, 0, unsupportedForDifferentSizes); + /// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64, + /// and Unsupported for all other scalar types T. + static SizeAndActionsVec + unsupportedForDifferentSizes(const SizeAndActionsVec &v) { + using namespace LegacyLegalizeActions; + return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported, + Unsupported); + } + + /// A SizeChangeStrategy for the common case where legalization for a + /// particular operation consists of widening the type to a large legal type, + /// unless there is no such type and then instead it should be narrowed to the + /// largest legal type. + static SizeAndActionsVec + widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) { + using namespace LegacyLegalizeActions; + assert(v.size() > 0 && + "At least one size that can be legalized towards is needed" + " for this SizeChangeStrategy"); + return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar, + NarrowScalar); + } + + static SizeAndActionsVec + widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) { + using namespace LegacyLegalizeActions; + return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar, + Unsupported); + } + + static SizeAndActionsVec + narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) { + using namespace LegacyLegalizeActions; + return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar, + Unsupported); + } + + static SizeAndActionsVec + narrowToSmallerAndWidenToSmallest(const SizeAndActionsVec &v) { + using namespace LegacyLegalizeActions; + assert(v.size() > 0 && + "At least one size that can be legalized towards is needed" + " for this SizeChangeStrategy"); + return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar, + WidenScalar); + } + + /// A SizeChangeStrategy for the common case where legalization for a + /// particular vector operation consists of having more elements in the + /// vector, to a type that is legal. Unless there is no such type and then + /// instead it should be legalized towards the widest vector that's still + /// legal. E.g. + /// setAction({G_ADD, LLT::vector(8, 8)}, Legal); + /// setAction({G_ADD, LLT::vector(16, 8)}, Legal); + /// setAction({G_ADD, LLT::vector(2, 32)}, Legal); + /// setAction({G_ADD, LLT::vector(4, 32)}, Legal); + /// setLegalizeVectorElementToDifferentSizeStrategy( + /// G_ADD, 0, moreToWiderTypesAndLessToWidest); + /// will result in the following getAction results: + /// * getAction({G_ADD, LLT::vector(8,8)}) returns + /// (Legal, vector(8,8)). + /// * getAction({G_ADD, LLT::vector(9,8)}) returns + /// (MoreElements, vector(16,8)). + /// * getAction({G_ADD, LLT::vector(8,32)}) returns + /// (FewerElements, vector(4,32)). + static SizeAndActionsVec + moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) { + using namespace LegacyLegalizeActions; + return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements, + FewerElements); + } + + /// Helper function to implement many typical SizeChangeStrategy functions. + static SizeAndActionsVec increaseToLargerTypesAndDecreaseToLargest( + const SizeAndActionsVec &v, + LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction, + LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction); + /// Helper function to implement many typical SizeChangeStrategy functions. + static SizeAndActionsVec decreaseToSmallerTypesAndIncreaseToSmallest( + const SizeAndActionsVec &v, + LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction, + LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction); + + LegacyLegalizeActionStep getAction(const LegalityQuery &Query) const; + + unsigned getOpcodeIdxForOpcode(unsigned Opcode) const; + +private: + /// Determine what action should be taken to legalize the given generic + /// instruction opcode, type-index and type. Requires computeTables to have + /// been called. + /// + /// \returns a pair consisting of the kind of legalization that should be + /// performed and the destination type. + std::pair + getAspectAction(const InstrAspect &Aspect) const; + + /// The SizeAndActionsVec is a representation mapping between all natural + /// numbers and an Action. The natural number represents the bit size of + /// the InstrAspect. For example, for a target with native support for 32-bit + /// and 64-bit additions, you'd express that as: + /// setScalarAction(G_ADD, 0, + /// {{1, WidenScalar}, // bit sizes [ 1, 31[ + /// {32, Legal}, // bit sizes [32, 33[ + /// {33, WidenScalar}, // bit sizes [33, 64[ + /// {64, Legal}, // bit sizes [64, 65[ + /// {65, NarrowScalar} // bit sizes [65, +inf[ + /// }); + /// It may be that only 64-bit pointers are supported on your target: + /// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1), + /// {{1, Unsupported}, // bit sizes [ 1, 63[ + /// {64, Legal}, // bit sizes [64, 65[ + /// {65, Unsupported}, // bit sizes [65, +inf[ + /// }); + void setScalarAction(const unsigned Opcode, const unsigned TypeIndex, + const SizeAndActionsVec &SizeAndActions) { + const unsigned OpcodeIdx = Opcode - FirstOp; + SmallVector &Actions = ScalarActions[OpcodeIdx]; + setActions(TypeIndex, Actions, SizeAndActions); + } + void setPointerAction(const unsigned Opcode, const unsigned TypeIndex, + const unsigned AddressSpace, + const SizeAndActionsVec &SizeAndActions) { + const unsigned OpcodeIdx = Opcode - FirstOp; + if (AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace) == + AddrSpace2PointerActions[OpcodeIdx].end()) + AddrSpace2PointerActions[OpcodeIdx][AddressSpace] = {{}}; + SmallVector &Actions = + AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second; + setActions(TypeIndex, Actions, SizeAndActions); + } + + /// If an operation on a given vector type (say ) isn't explicitly + /// specified, we proceed in 2 stages. First we legalize the underlying scalar + /// (so that there's at least one legal vector with that scalar), then we + /// adjust the number of elements in the vector so that it is legal. The + /// desired action in the first step is controlled by this function. + void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex, + const SizeAndActionsVec &SizeAndActions) { + unsigned OpcodeIdx = Opcode - FirstOp; + SmallVector &Actions = + ScalarInVectorActions[OpcodeIdx]; + setActions(TypeIndex, Actions, SizeAndActions); + } + + /// See also setScalarInVectorAction. + /// This function let's you specify the number of elements in a vector that + /// are legal for a legal element size. + void setVectorNumElementAction(const unsigned Opcode, + const unsigned TypeIndex, + const unsigned ElementSize, + const SizeAndActionsVec &SizeAndActions) { + const unsigned OpcodeIdx = Opcode - FirstOp; + if (NumElements2Actions[OpcodeIdx].find(ElementSize) == + NumElements2Actions[OpcodeIdx].end()) + NumElements2Actions[OpcodeIdx][ElementSize] = {{}}; + SmallVector &Actions = + NumElements2Actions[OpcodeIdx].find(ElementSize)->second; + setActions(TypeIndex, Actions, SizeAndActions); + } + + /// A partial SizeAndActionsVec potentially doesn't cover all bit sizes, + /// i.e. it's OK if it doesn't start from size 1. + static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) { + using namespace LegacyLegalizeActions; +#ifndef NDEBUG + // The sizes should be in increasing order + int prev_size = -1; + for(auto SizeAndAction: v) { + assert(SizeAndAction.first > prev_size); + prev_size = SizeAndAction.first; + } + // - for every Widen action, there should be a larger bitsize that + // can be legalized towards (e.g. Legal, Lower, Libcall or Custom + // action). + // - for every Narrow action, there should be a smaller bitsize that + // can be legalized towards. + int SmallestNarrowIdx = -1; + int LargestWidenIdx = -1; + int SmallestLegalizableToSameSizeIdx = -1; + int LargestLegalizableToSameSizeIdx = -1; + for(size_t i=0; i SmallestLegalizableToSameSizeIdx); + } + if (LargestWidenIdx != -1) + assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx); +#endif + } + + /// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with + /// from size 1. + static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) { +#ifndef NDEBUG + // Data structure invariant: The first bit size must be size 1. + assert(v.size() >= 1); + assert(v[0].first == 1); + checkPartialSizeAndActionsVector(v); +#endif + } + + /// Sets actions for all bit sizes on a particular generic opcode, type + /// index and scalar or pointer type. + void setActions(unsigned TypeIndex, + SmallVector &Actions, + const SizeAndActionsVec &SizeAndActions) { + checkFullSizeAndActionsVector(SizeAndActions); + if (Actions.size() <= TypeIndex) + Actions.resize(TypeIndex + 1); + Actions[TypeIndex] = SizeAndActions; + } + + static SizeAndAction findAction(const SizeAndActionsVec &Vec, + const uint32_t Size); + + /// Returns the next action needed to get the scalar or pointer type closer + /// to being legal + /// E.g. findLegalAction({G_REM, 13}) should return + /// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will + /// probably be called, which should return (Lower, 32). + /// This is assuming the setScalarAction on G_REM was something like: + /// setScalarAction(G_REM, 0, + /// {{1, WidenScalar}, // bit sizes [ 1, 31[ + /// {32, Lower}, // bit sizes [32, 33[ + /// {33, NarrowScalar} // bit sizes [65, +inf[ + /// }); + std::pair + findScalarLegalAction(const InstrAspect &Aspect) const; + + /// Returns the next action needed towards legalizing the vector type. + std::pair + findVectorLegalAction(const InstrAspect &Aspect) const; + + static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START; + static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; + + // Data structures used temporarily during construction of legality data: + using TypeMap = DenseMap; + SmallVector SpecifiedActions[LastOp - FirstOp + 1]; + SmallVector + ScalarSizeChangeStrategies[LastOp - FirstOp + 1]; + SmallVector + VectorElementSizeChangeStrategies[LastOp - FirstOp + 1]; + bool TablesInitialized; + + // Data structures used by getAction: + SmallVector ScalarActions[LastOp - FirstOp + 1]; + SmallVector ScalarInVectorActions[LastOp - FirstOp + 1]; + std::unordered_map> + AddrSpace2PointerActions[LastOp - FirstOp + 1]; + std::unordered_map> + NumElements2Actions[LastOp - FirstOp + 1]; +}; + +} // end namespace llvm + +#endif // define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -20,6 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/Support/CommandLine.h" @@ -100,23 +101,6 @@ using LegalizeActions::LegalizeAction; -/// Legalization is decided based on an instruction's opcode, which type slot -/// we're considering, and what the existing type is. These aspects are gathered -/// together for convenience in the InstrAspect class. -struct InstrAspect { - unsigned Opcode; - unsigned Idx = 0; - LLT Type; - - InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {} - InstrAspect(unsigned Opcode, unsigned Idx, LLT Type) - : Opcode(Opcode), Idx(Idx), Type(Type) {} - - bool operator==(const InstrAspect &RHS) const { - return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type; - } -}; - /// The LegalityQuery object bundles together all the information that's needed /// to decide whether a given operation is legal or not. /// For efficiency, it doesn't make a copy of Types so care must be taken not @@ -159,6 +143,45 @@ const LLT NewType) : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {} + LegalizeActionStep(LegacyLegalizeActionStep Step) + : TypeIdx(Step.TypeIdx), NewType(Step.NewType) { + switch (Step.Action) { + case LegacyLegalizeActions::Legal: + Action = LegalizeActions::Legal; + break; + case LegacyLegalizeActions::NarrowScalar: + Action = LegalizeActions::NarrowScalar; + break; + case LegacyLegalizeActions::WidenScalar: + Action = LegalizeActions::WidenScalar; + break; + case LegacyLegalizeActions::FewerElements: + Action = LegalizeActions::FewerElements; + break; + case LegacyLegalizeActions::MoreElements: + Action = LegalizeActions::MoreElements; + break; + case LegacyLegalizeActions::Bitcast: + Action = LegalizeActions::Bitcast; + break; + case LegacyLegalizeActions::Lower: + Action = LegalizeActions::Lower; + break; + case LegacyLegalizeActions::Libcall: + Action = LegalizeActions::Libcall; + break; + case LegacyLegalizeActions::Custom: + Action = LegalizeActions::Custom; + break; + case LegacyLegalizeActions::Unsupported: + Action = LegalizeActions::Unsupported; + break; + case LegacyLegalizeActions::NotFound: + Action = LegalizeActions::NotFound; + break; + } + } + bool operator==(const LegalizeActionStep &RHS) const { return std::tie(Action, TypeIdx, NewType) == std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType); @@ -1057,179 +1080,20 @@ class LegalizerInfo { public: - LegalizerInfo(); virtual ~LegalizerInfo() = default; + const LegacyLegalizerInfo &getLegacyLegalizerInfo() const { + return LegacyInfo; + } + LegacyLegalizerInfo &getLegacyLegalizerInfo() { return LegacyInfo; } + unsigned getOpcodeIdxForOpcode(unsigned Opcode) const; unsigned getActionDefinitionsIdx(unsigned Opcode) const; - /// Compute any ancillary tables needed to quickly decide how an operation - /// should be handled. This must be called after all "set*Action"methods but - /// before any query is made or incorrect results may be returned. - void computeTables(); - /// Perform simple self-diagnostic and assert if there is anything obviously /// wrong with the actions set up. void verify(const MCInstrInfo &MII) const; - static bool needsLegalizingToDifferentSize(const LegalizeAction Action) { - using namespace LegalizeActions; - switch (Action) { - case NarrowScalar: - case WidenScalar: - case FewerElements: - case MoreElements: - case Unsupported: - return true; - default: - return false; - } - } - - using SizeAndAction = std::pair; - using SizeAndActionsVec = std::vector; - using SizeChangeStrategy = - std::function; - - /// More friendly way to set an action for common types that have an LLT - /// representation. - /// The LegalizeAction must be one for which NeedsLegalizingToDifferentSize - /// returns false. - void setAction(const InstrAspect &Aspect, LegalizeAction Action) { - assert(!needsLegalizingToDifferentSize(Action)); - TablesInitialized = false; - const unsigned OpcodeIdx = Aspect.Opcode - FirstOp; - if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx) - SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1); - SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action; - } - - /// The setAction calls record the non-size-changing legalization actions - /// to take on specificly-sized types. The SizeChangeStrategy defines what - /// to do when the size of the type needs to be changed to reach a legally - /// sized type (i.e., one that was defined through a setAction call). - /// e.g. - /// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal); - /// setLegalizeScalarToDifferentSizeStrategy( - /// G_ADD, 0, widenToLargerTypesAndNarrowToLargest); - /// will end up defining getAction({G_ADD, 0, T}) to return the following - /// actions for different scalar types T: - /// LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)} - /// LLT::scalar(32): {Legal, 0, LLT::scalar(32)} - /// LLT::scalar(33)..: {NarrowScalar, 0, LLT::scalar(32)} - /// - /// If no SizeChangeAction gets defined, through this function, - /// the default is unsupportedForDifferentSizes. - void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode, - const unsigned TypeIdx, - SizeChangeStrategy S) { - const unsigned OpcodeIdx = Opcode - FirstOp; - if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx) - ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1); - ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S; - } - - /// See also setLegalizeScalarToDifferentSizeStrategy. - /// This function allows to set the SizeChangeStrategy for vector elements. - void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode, - const unsigned TypeIdx, - SizeChangeStrategy S) { - const unsigned OpcodeIdx = Opcode - FirstOp; - if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx) - VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1); - VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S; - } - - /// A SizeChangeStrategy for the common case where legalization for a - /// particular operation consists of only supporting a specific set of type - /// sizes. E.g. - /// setAction ({G_DIV, 0, LLT::scalar(32)}, Legal); - /// setAction ({G_DIV, 0, LLT::scalar(64)}, Legal); - /// setLegalizeScalarToDifferentSizeStrategy( - /// G_DIV, 0, unsupportedForDifferentSizes); - /// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64, - /// and Unsupported for all other scalar types T. - static SizeAndActionsVec - unsupportedForDifferentSizes(const SizeAndActionsVec &v) { - using namespace LegalizeActions; - return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported, - Unsupported); - } - - /// A SizeChangeStrategy for the common case where legalization for a - /// particular operation consists of widening the type to a large legal type, - /// unless there is no such type and then instead it should be narrowed to the - /// largest legal type. - static SizeAndActionsVec - widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) { - using namespace LegalizeActions; - assert(v.size() > 0 && - "At least one size that can be legalized towards is needed" - " for this SizeChangeStrategy"); - return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar, - NarrowScalar); - } - - static SizeAndActionsVec - widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) { - using namespace LegalizeActions; - return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar, - Unsupported); - } - - static SizeAndActionsVec - narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) { - using namespace LegalizeActions; - return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar, - Unsupported); - } - - static SizeAndActionsVec - narrowToSmallerAndWidenToSmallest(const SizeAndActionsVec &v) { - using namespace LegalizeActions; - assert(v.size() > 0 && - "At least one size that can be legalized towards is needed" - " for this SizeChangeStrategy"); - return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar, - WidenScalar); - } - - /// A SizeChangeStrategy for the common case where legalization for a - /// particular vector operation consists of having more elements in the - /// vector, to a type that is legal. Unless there is no such type and then - /// instead it should be legalized towards the widest vector that's still - /// legal. E.g. - /// setAction({G_ADD, LLT::vector(8, 8)}, Legal); - /// setAction({G_ADD, LLT::vector(16, 8)}, Legal); - /// setAction({G_ADD, LLT::vector(2, 32)}, Legal); - /// setAction({G_ADD, LLT::vector(4, 32)}, Legal); - /// setLegalizeVectorElementToDifferentSizeStrategy( - /// G_ADD, 0, moreToWiderTypesAndLessToWidest); - /// will result in the following getAction results: - /// * getAction({G_ADD, LLT::vector(8,8)}) returns - /// (Legal, vector(8,8)). - /// * getAction({G_ADD, LLT::vector(9,8)}) returns - /// (MoreElements, vector(16,8)). - /// * getAction({G_ADD, LLT::vector(8,32)}) returns - /// (FewerElements, vector(4,32)). - static SizeAndActionsVec - moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) { - using namespace LegalizeActions; - return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements, - FewerElements); - } - - /// Helper function to implement many typical SizeChangeStrategy functions. - static SizeAndActionsVec - increaseToLargerTypesAndDecreaseToLargest(const SizeAndActionsVec &v, - LegalizeAction IncreaseAction, - LegalizeAction DecreaseAction); - /// Helper function to implement many typical SizeChangeStrategy functions. - static SizeAndActionsVec - decreaseToSmallerTypesAndIncreaseToSmallest(const SizeAndActionsVec &v, - LegalizeAction DecreaseAction, - LegalizeAction IncreaseAction); - /// Get the action definitions for the given opcode. Use this to run a /// LegalityQuery through the definitions. const LegalizeRuleSet &getActionDefinitions(unsigned Opcode) const; @@ -1306,191 +1170,11 @@ virtual unsigned getExtOpcodeForWideningConstant(LLT SmallTy) const; private: - /// Determine what action should be taken to legalize the given generic - /// instruction opcode, type-index and type. Requires computeTables to have - /// been called. - /// - /// \returns a pair consisting of the kind of legalization that should be - /// performed and the destination type. - std::pair - getAspectAction(const InstrAspect &Aspect) const; - - /// The SizeAndActionsVec is a representation mapping between all natural - /// numbers and an Action. The natural number represents the bit size of - /// the InstrAspect. For example, for a target with native support for 32-bit - /// and 64-bit additions, you'd express that as: - /// setScalarAction(G_ADD, 0, - /// {{1, WidenScalar}, // bit sizes [ 1, 31[ - /// {32, Legal}, // bit sizes [32, 33[ - /// {33, WidenScalar}, // bit sizes [33, 64[ - /// {64, Legal}, // bit sizes [64, 65[ - /// {65, NarrowScalar} // bit sizes [65, +inf[ - /// }); - /// It may be that only 64-bit pointers are supported on your target: - /// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1), - /// {{1, Unsupported}, // bit sizes [ 1, 63[ - /// {64, Legal}, // bit sizes [64, 65[ - /// {65, Unsupported}, // bit sizes [65, +inf[ - /// }); - void setScalarAction(const unsigned Opcode, const unsigned TypeIndex, - const SizeAndActionsVec &SizeAndActions) { - const unsigned OpcodeIdx = Opcode - FirstOp; - SmallVector &Actions = ScalarActions[OpcodeIdx]; - setActions(TypeIndex, Actions, SizeAndActions); - } - void setPointerAction(const unsigned Opcode, const unsigned TypeIndex, - const unsigned AddressSpace, - const SizeAndActionsVec &SizeAndActions) { - const unsigned OpcodeIdx = Opcode - FirstOp; - if (AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace) == - AddrSpace2PointerActions[OpcodeIdx].end()) - AddrSpace2PointerActions[OpcodeIdx][AddressSpace] = {{}}; - SmallVector &Actions = - AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second; - setActions(TypeIndex, Actions, SizeAndActions); - } - - /// If an operation on a given vector type (say ) isn't explicitly - /// specified, we proceed in 2 stages. First we legalize the underlying scalar - /// (so that there's at least one legal vector with that scalar), then we - /// adjust the number of elements in the vector so that it is legal. The - /// desired action in the first step is controlled by this function. - void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex, - const SizeAndActionsVec &SizeAndActions) { - unsigned OpcodeIdx = Opcode - FirstOp; - SmallVector &Actions = - ScalarInVectorActions[OpcodeIdx]; - setActions(TypeIndex, Actions, SizeAndActions); - } - - /// See also setScalarInVectorAction. - /// This function let's you specify the number of elements in a vector that - /// are legal for a legal element size. - void setVectorNumElementAction(const unsigned Opcode, - const unsigned TypeIndex, - const unsigned ElementSize, - const SizeAndActionsVec &SizeAndActions) { - const unsigned OpcodeIdx = Opcode - FirstOp; - if (NumElements2Actions[OpcodeIdx].find(ElementSize) == - NumElements2Actions[OpcodeIdx].end()) - NumElements2Actions[OpcodeIdx][ElementSize] = {{}}; - SmallVector &Actions = - NumElements2Actions[OpcodeIdx].find(ElementSize)->second; - setActions(TypeIndex, Actions, SizeAndActions); - } - - /// A partial SizeAndActionsVec potentially doesn't cover all bit sizes, - /// i.e. it's OK if it doesn't start from size 1. - static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) { - using namespace LegalizeActions; -#ifndef NDEBUG - // The sizes should be in increasing order - int prev_size = -1; - for(auto SizeAndAction: v) { - assert(SizeAndAction.first > prev_size); - prev_size = SizeAndAction.first; - } - // - for every Widen action, there should be a larger bitsize that - // can be legalized towards (e.g. Legal, Lower, Libcall or Custom - // action). - // - for every Narrow action, there should be a smaller bitsize that - // can be legalized towards. - int SmallestNarrowIdx = -1; - int LargestWidenIdx = -1; - int SmallestLegalizableToSameSizeIdx = -1; - int LargestLegalizableToSameSizeIdx = -1; - for(size_t i=0; i SmallestLegalizableToSameSizeIdx); - } - if (LargestWidenIdx != -1) - assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx); -#endif - } - - /// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with - /// from size 1. - static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) { -#ifndef NDEBUG - // Data structure invariant: The first bit size must be size 1. - assert(v.size() >= 1); - assert(v[0].first == 1); - checkPartialSizeAndActionsVector(v); -#endif - } - - /// Sets actions for all bit sizes on a particular generic opcode, type - /// index and scalar or pointer type. - void setActions(unsigned TypeIndex, - SmallVector &Actions, - const SizeAndActionsVec &SizeAndActions) { - checkFullSizeAndActionsVector(SizeAndActions); - if (Actions.size() <= TypeIndex) - Actions.resize(TypeIndex + 1); - Actions[TypeIndex] = SizeAndActions; - } - - static SizeAndAction findAction(const SizeAndActionsVec &Vec, - const uint32_t Size); - - /// Returns the next action needed to get the scalar or pointer type closer - /// to being legal - /// E.g. findLegalAction({G_REM, 13}) should return - /// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will - /// probably be called, which should return (Lower, 32). - /// This is assuming the setScalarAction on G_REM was something like: - /// setScalarAction(G_REM, 0, - /// {{1, WidenScalar}, // bit sizes [ 1, 31[ - /// {32, Lower}, // bit sizes [32, 33[ - /// {33, NarrowScalar} // bit sizes [65, +inf[ - /// }); - std::pair - findScalarLegalAction(const InstrAspect &Aspect) const; - - /// Returns the next action needed towards legalizing the vector type. - std::pair - findVectorLegalAction(const InstrAspect &Aspect) const; - static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START; static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; - // Data structures used temporarily during construction of legality data: - using TypeMap = DenseMap; - SmallVector SpecifiedActions[LastOp - FirstOp + 1]; - SmallVector - ScalarSizeChangeStrategies[LastOp - FirstOp + 1]; - SmallVector - VectorElementSizeChangeStrategies[LastOp - FirstOp + 1]; - bool TablesInitialized; - - // Data structures used by getAction: - SmallVector ScalarActions[LastOp - FirstOp + 1]; - SmallVector ScalarInVectorActions[LastOp - FirstOp + 1]; - std::unordered_map> - AddrSpace2PointerActions[LastOp - FirstOp + 1]; - std::unordered_map> - NumElements2Actions[LastOp - FirstOp + 1]; - LegalizeRuleSet RulesForOpcode[LastOp - FirstOp + 1]; + LegacyLegalizerInfo LegacyInfo; }; #ifndef NDEBUG diff --git a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt --- a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt +++ b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt @@ -16,6 +16,7 @@ Legalizer.cpp LegalizerHelper.cpp LegalizerInfo.cpp + LegacyLegalizerInfo.cpp Localizer.cpp LostDebugLocObserver.cpp MachineIRBuilder.cpp diff --git a/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp @@ -0,0 +1,344 @@ +//===- lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp - Legalizer ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implement an interface to specify and query how an illegal operation on a +// given type should be expanded. +// +// Issues to be resolved: +// + Make it fast. +// + Support weird types like i3, <7 x i3>, ... +// + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...) +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include + +using namespace llvm; +using namespace LegacyLegalizeActions; + +#define DEBUG_TYPE "legalizer-info" + +LegacyLegalizerInfo::LegacyLegalizerInfo() : TablesInitialized(false) { + // Set defaults. + // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the + // fundamental load/store Jakob proposed. Once loads & stores are supported. + setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}}); + setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}}); + setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}}); + setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}}); + setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}}); + + setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}}); + setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}}); + + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall); + + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall); + setLegalizeScalarToDifferentSizeStrategy( + TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall); + setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}}); +} + +void LegacyLegalizerInfo::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 AddressSpace2SpecifiedActions; + // For vector types: + std::map ElemSize2SpecifiedActions; + for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) { + const LLT Type = LLT2Action.first; + const LegacyLegalizeAction 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]; + llvm::sort(ScalarSpecifiedActions); + checkPartialSizeAndActionsVector(ScalarSpecifiedActions); + setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions)); + } + + // 2. Handle pointer types + for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) { + llvm::sort(PointerSpecifiedActions.second); + 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) { + llvm::sort(VectorSpecifiedActions.second); + 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)); + } + llvm::sort(ElementSizesSeen); + SizeChangeStrategy VectorElementSizeChangeStrategy = + &unsupportedForDifferentSizes; + if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() && + VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) + VectorElementSizeChangeStrategy = + VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx]; + setScalarInVectorAction( + Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen)); + } + } + + 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 +LegacyLegalizerInfo::getAspectAction(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. + if (Aspect.Type.isScalar() || Aspect.Type.isPointer()) + return findScalarLegalAction(Aspect); + assert(Aspect.Type.isVector()); + return findVectorLegalAction(Aspect); +} + +LegacyLegalizerInfo::SizeAndActionsVec +LegacyLegalizerInfo::increaseToLargerTypesAndDecreaseToLargest( + const SizeAndActionsVec &v, LegacyLegalizeAction IncreaseAction, + LegacyLegalizeAction DecreaseAction) { + SizeAndActionsVec result; + unsigned LargestSizeSoFar = 0; + if (v.size() >= 1 && v[0].first != 1) + result.push_back({1, IncreaseAction}); + for (size_t i = 0; i < v.size(); ++i) { + result.push_back(v[i]); + LargestSizeSoFar = v[i].first; + if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) { + result.push_back({LargestSizeSoFar + 1, IncreaseAction}); + LargestSizeSoFar = v[i].first + 1; + } + } + result.push_back({LargestSizeSoFar + 1, DecreaseAction}); + return result; +} + +LegacyLegalizerInfo::SizeAndActionsVec +LegacyLegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest( + const SizeAndActionsVec &v, LegacyLegalizeAction DecreaseAction, + LegacyLegalizeAction IncreaseAction) { + SizeAndActionsVec result; + if (v.size() == 0 || v[0].first != 1) + result.push_back({1, IncreaseAction}); + for (size_t i = 0; i < v.size(); ++i) { + result.push_back(v[i]); + if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) { + result.push_back({v[i].first + 1, DecreaseAction}); + } + } + return result; +} + +LegacyLegalizerInfo::SizeAndAction +LegacyLegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) { + assert(Size >= 1); + // Find the last element in Vec that has a bitsize equal to or smaller than + // the requested bit size. + // That is the element just before the first element that is bigger than Size. + auto It = partition_point( + Vec, [=](const SizeAndAction &A) { return A.first <= Size; }); + assert(It != Vec.begin() && "Does Vec not start with size 1?"); + int VecIdx = It - Vec.begin() - 1; + + LegacyLegalizeAction Action = Vec[VecIdx].second; + switch (Action) { + case Legal: + case Bitcast: + case Lower: + case Libcall: + case Custom: + return {Size, Action}; + case FewerElements: + // FIXME: is this special case still needed and correct? + // Special case for scalarization: + if (Vec == SizeAndActionsVec({{1, FewerElements}})) + return {1, FewerElements}; + LLVM_FALLTHROUGH; + case NarrowScalar: { + // The following needs to be a loop, as for now, we do allow needing to + // go over "Unsupported" bit sizes before finding a legalizable bit size. + // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8, + // we need to iterate over s9, and then to s32 to return (s32, Legal). + // If we want to get rid of the below loop, we should have stronger asserts + // when building the SizeAndActionsVecs, probably not allowing + // "Unsupported" unless at the ends of the vector. + for (int i = VecIdx - 1; i >= 0; --i) + if (!needsLegalizingToDifferentSize(Vec[i].second) && + Vec[i].second != Unsupported) + return {Vec[i].first, Action}; + llvm_unreachable(""); + } + case WidenScalar: + case MoreElements: { + // See above, the following needs to be a loop, at least for now. + for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i) + if (!needsLegalizingToDifferentSize(Vec[i].second) && + Vec[i].second != Unsupported) + return {Vec[i].first, Action}; + llvm_unreachable(""); + } + case Unsupported: + return {Size, Unsupported}; + case NotFound: + llvm_unreachable("NotFound"); + } + llvm_unreachable("Action has an unknown enum value"); +} + +std::pair +LegacyLegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const { + assert(Aspect.Type.isScalar() || Aspect.Type.isPointer()); + if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) + return {NotFound, LLT()}; + const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode); + if (Aspect.Type.isPointer() && + AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) == + AddrSpace2PointerActions[OpcodeIdx].end()) { + return {NotFound, LLT()}; + } + const SmallVector &Actions = + Aspect.Type.isPointer() + ? AddrSpace2PointerActions[OpcodeIdx] + .find(Aspect.Type.getAddressSpace()) + ->second + : ScalarActions[OpcodeIdx]; + if (Aspect.Idx >= Actions.size()) + return {NotFound, LLT()}; + const SizeAndActionsVec &Vec = Actions[Aspect.Idx]; + // FIXME: speed up this search, e.g. by using a results cache for repeated + // queries? + auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits()); + return {SizeAndAction.second, + Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first) + : LLT::pointer(Aspect.Type.getAddressSpace(), + SizeAndAction.first)}; +} + +std::pair +LegacyLegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const { + assert(Aspect.Type.isVector()); + // First legalize the vector element size, then legalize the number of + // lanes in the vector. + if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) + return {NotFound, Aspect.Type}; + const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode); + const unsigned TypeIdx = Aspect.Idx; + if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size()) + return {NotFound, Aspect.Type}; + const SizeAndActionsVec &ElemSizeVec = + ScalarInVectorActions[OpcodeIdx][TypeIdx]; + + LLT IntermediateType; + auto ElementSizeAndAction = + findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits()); + IntermediateType = + LLT::vector(Aspect.Type.getNumElements(), ElementSizeAndAction.first); + if (ElementSizeAndAction.second != Legal) + return {ElementSizeAndAction.second, IntermediateType}; + + auto i = NumElements2Actions[OpcodeIdx].find( + IntermediateType.getScalarSizeInBits()); + if (i == NumElements2Actions[OpcodeIdx].end()) { + return {NotFound, IntermediateType}; + } + const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx]; + auto NumElementsAndAction = + findAction(NumElementsVec, IntermediateType.getNumElements()); + return {NumElementsAndAction.second, + LLT::vector(NumElementsAndAction.first, + IntermediateType.getScalarSizeInBits())}; +} + +unsigned LegacyLegalizerInfo::getOpcodeIdxForOpcode(unsigned Opcode) const { + assert(Opcode >= FirstOp && Opcode <= LastOp && "Unsupported opcode"); + return Opcode - FirstOp; +} + + +LegacyLegalizeActionStep +LegacyLegalizerInfo::getAction(const LegalityQuery &Query) const { + for (unsigned i = 0; i < Query.Types.size(); ++i) { + auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]}); + if (Action.first != Legal) { + LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Action=" + << Action.first << ", " << Action.second << "\n"); + return {Action.first, i, Action.second}; + } else + LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Legal\n"); + } + LLVM_DEBUG(dbgs() << ".. (legacy) Legal\n"); + return {Legal, 0, LLT{}}; +} + diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp --- a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -9,11 +9,6 @@ // Implement an interface to specify and query how an illegal operation on a // given type should be expanded. // -// Issues to be resolved: -// + Make it fast. -// + Support weird types like i3, <7 x i3>, ... -// + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...) -// //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" @@ -256,146 +251,6 @@ #endif } -LegalizerInfo::LegalizerInfo() : TablesInitialized(false) { - // Set defaults. - // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the - // fundamental load/store Jakob proposed. Once loads & stores are supported. - setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}}); - setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}}); - setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}}); - setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}}); - setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}}); - - setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}}); - setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}}); - - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall); - - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall); - setLegalizeScalarToDifferentSizeStrategy( - TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall); - setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}}); -} - -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 AddressSpace2SpecifiedActions; - // For vector types: - std::map 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]; - llvm::sort(ScalarSpecifiedActions); - checkPartialSizeAndActionsVector(ScalarSpecifiedActions); - setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions)); - } - - // 2. Handle pointer types - for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) { - llvm::sort(PointerSpecifiedActions.second); - 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) { - llvm::sort(VectorSpecifiedActions.second); - 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)); - } - llvm::sort(ElementSizesSeen); - SizeChangeStrategy VectorElementSizeChangeStrategy = - &unsupportedForDifferentSizes; - if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() && - VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr) - VectorElementSizeChangeStrategy = - VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx]; - setScalarInVectorAction( - Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen)); - } - } - - 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::getAspectAction(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. - if (Aspect.Type.isScalar() || Aspect.Type.isPointer()) - return findScalarLegalAction(Aspect); - assert(Aspect.Type.isVector()); - return findVectorLegalAction(Aspect); -} - /// Helper function to get LLT for the given type index. static LLT getTypeFromTypeIdx(const MachineInstr &MI, const MachineRegisterInfo &MRI, unsigned OpIdx, @@ -469,17 +324,7 @@ return Step; } - for (unsigned i = 0; i < Query.Types.size(); ++i) { - auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]}); - if (Action.first != Legal) { - LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Action=" - << Action.first << ", " << Action.second << "\n"); - return {Action.first, i, Action.second}; - } else - LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Legal\n"); - } - LLVM_DEBUG(dbgs() << ".. (legacy) Legal\n"); - return {Legal, 0, LLT{}}; + return getLegacyLegalizerInfo().getAction(Query); } LegalizeActionStep @@ -526,163 +371,6 @@ return Action == Legal || Action == Custom; } -LegalizerInfo::SizeAndActionsVec -LegalizerInfo::increaseToLargerTypesAndDecreaseToLargest( - const SizeAndActionsVec &v, LegalizeAction IncreaseAction, - LegalizeAction DecreaseAction) { - SizeAndActionsVec result; - unsigned LargestSizeSoFar = 0; - if (v.size() >= 1 && v[0].first != 1) - result.push_back({1, IncreaseAction}); - for (size_t i = 0; i < v.size(); ++i) { - result.push_back(v[i]); - LargestSizeSoFar = v[i].first; - if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) { - result.push_back({LargestSizeSoFar + 1, IncreaseAction}); - LargestSizeSoFar = v[i].first + 1; - } - } - result.push_back({LargestSizeSoFar + 1, DecreaseAction}); - return result; -} - -LegalizerInfo::SizeAndActionsVec -LegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest( - const SizeAndActionsVec &v, LegalizeAction DecreaseAction, - LegalizeAction IncreaseAction) { - SizeAndActionsVec result; - if (v.size() == 0 || v[0].first != 1) - result.push_back({1, IncreaseAction}); - for (size_t i = 0; i < v.size(); ++i) { - result.push_back(v[i]); - if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) { - result.push_back({v[i].first + 1, DecreaseAction}); - } - } - return result; -} - -LegalizerInfo::SizeAndAction -LegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) { - assert(Size >= 1); - // Find the last element in Vec that has a bitsize equal to or smaller than - // the requested bit size. - // That is the element just before the first element that is bigger than Size. - auto It = partition_point( - Vec, [=](const SizeAndAction &A) { return A.first <= Size; }); - assert(It != Vec.begin() && "Does Vec not start with size 1?"); - int VecIdx = It - Vec.begin() - 1; - - LegalizeAction Action = Vec[VecIdx].second; - switch (Action) { - case Legal: - case Bitcast: - case Lower: - case Libcall: - case Custom: - return {Size, Action}; - case FewerElements: - // FIXME: is this special case still needed and correct? - // Special case for scalarization: - if (Vec == SizeAndActionsVec({{1, FewerElements}})) - return {1, FewerElements}; - LLVM_FALLTHROUGH; - case NarrowScalar: { - // The following needs to be a loop, as for now, we do allow needing to - // go over "Unsupported" bit sizes before finding a legalizable bit size. - // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8, - // we need to iterate over s9, and then to s32 to return (s32, Legal). - // If we want to get rid of the below loop, we should have stronger asserts - // when building the SizeAndActionsVecs, probably not allowing - // "Unsupported" unless at the ends of the vector. - for (int i = VecIdx - 1; i >= 0; --i) - if (!needsLegalizingToDifferentSize(Vec[i].second) && - Vec[i].second != Unsupported) - return {Vec[i].first, Action}; - llvm_unreachable(""); - } - case WidenScalar: - case MoreElements: { - // See above, the following needs to be a loop, at least for now. - for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i) - if (!needsLegalizingToDifferentSize(Vec[i].second) && - Vec[i].second != Unsupported) - return {Vec[i].first, Action}; - llvm_unreachable(""); - } - case Unsupported: - return {Size, Unsupported}; - case NotFound: - case UseLegacyRules: - llvm_unreachable("NotFound"); - } - llvm_unreachable("Action has an unknown enum value"); -} - -std::pair -LegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const { - assert(Aspect.Type.isScalar() || Aspect.Type.isPointer()); - if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) - return {NotFound, LLT()}; - const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode); - if (Aspect.Type.isPointer() && - AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) == - AddrSpace2PointerActions[OpcodeIdx].end()) { - return {NotFound, LLT()}; - } - const SmallVector &Actions = - Aspect.Type.isPointer() - ? AddrSpace2PointerActions[OpcodeIdx] - .find(Aspect.Type.getAddressSpace()) - ->second - : ScalarActions[OpcodeIdx]; - if (Aspect.Idx >= Actions.size()) - return {NotFound, LLT()}; - const SizeAndActionsVec &Vec = Actions[Aspect.Idx]; - // FIXME: speed up this search, e.g. by using a results cache for repeated - // queries? - auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits()); - return {SizeAndAction.second, - Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first) - : LLT::pointer(Aspect.Type.getAddressSpace(), - SizeAndAction.first)}; -} - -std::pair -LegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const { - assert(Aspect.Type.isVector()); - // First legalize the vector element size, then legalize the number of - // lanes in the vector. - if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp) - return {NotFound, Aspect.Type}; - const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode); - const unsigned TypeIdx = Aspect.Idx; - if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size()) - return {NotFound, Aspect.Type}; - const SizeAndActionsVec &ElemSizeVec = - ScalarInVectorActions[OpcodeIdx][TypeIdx]; - - LLT IntermediateType; - auto ElementSizeAndAction = - findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits()); - IntermediateType = - LLT::vector(Aspect.Type.getNumElements(), ElementSizeAndAction.first); - if (ElementSizeAndAction.second != Legal) - return {ElementSizeAndAction.second, IntermediateType}; - - auto i = NumElements2Actions[OpcodeIdx].find( - IntermediateType.getScalarSizeInBits()); - if (i == NumElements2Actions[OpcodeIdx].end()) { - return {NotFound, IntermediateType}; - } - const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx]; - auto NumElementsAndAction = - findAction(NumElementsVec, IntermediateType.getNumElements()); - return {NumElementsAndAction.second, - LLT::vector(NumElementsAndAction.first, - IntermediateType.getScalarSizeInBits())}; -} - unsigned LegalizerInfo::getExtOpcodeForWideningConstant(LLT SmallTy) const { return SmallTy.isByteSized() ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT; } diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp --- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp @@ -69,7 +69,7 @@ // FIXME: support subtargets which have neon/fp-armv8 disabled. if (!ST.hasNEON() || !ST.hasFPARMv8()) { - computeTables(); + getLegacyLegalizerInfo().computeTables(); return; } @@ -751,7 +751,7 @@ .maxScalarEltSameAsIf(always, 1, 0) .customFor({{s32, s32}, {s64, s64}}); - computeTables(); + getLegacyLegalizerInfo().computeTables(); verify(*ST.getInstrInfo()); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp @@ -501,8 +501,11 @@ const LLT MinScalarFPTy = ST.has16BitInsts() ? S16 : S32; - setAction({G_BRCOND, S1}, Legal); // VCC branches - setAction({G_BRCOND, S32}, Legal); // SCC branches + auto &LegacyInfo = getLegacyLegalizerInfo(); + LegacyInfo.setAction({G_BRCOND, S1}, + LegacyLegalizeActions::Legal); // VCC branches + LegacyInfo.setAction({G_BRCOND, S32}, + LegacyLegalizeActions::Legal); // SCC branches // TODO: All multiples of 32, vectors of pointers, all v2s16 pairs, more // elements for v3s16 @@ -650,7 +653,8 @@ .widenScalarToNextPow2(0, 32) .clampMaxNumElements(0, S32, 16); - setAction({G_FRAME_INDEX, PrivatePtr}, Legal); + LegacyInfo.setAction({G_FRAME_INDEX, PrivatePtr}, + LegacyLegalizeActions::Legal); // If the amount is divergent, we have to do a wave reduction to get the // maximum value, so this is expanded during RegBankSelect. @@ -660,7 +664,7 @@ getActionDefinitionsBuilder(G_GLOBAL_VALUE) .customIf(typeIsNot(0, PrivatePtr)); - setAction({G_BLOCK_ADDR, CodePtr}, Legal); + LegacyInfo.setAction({G_BLOCK_ADDR, CodePtr}, LegacyLegalizeActions::Legal); auto &FPOpActions = getActionDefinitionsBuilder( { G_FADD, G_FMUL, G_FMA, G_FCANONICALIZE}) @@ -1664,7 +1668,7 @@ G_INDEXED_ZEXTLOAD, G_INDEXED_STORE}) .unsupported(); - computeTables(); + getLegacyLegalizerInfo().computeTables(); verify(*ST.getInstrInfo()); } diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp --- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -33,29 +33,30 @@ /// In practice, not specifying those isn't a problem, and the below functions /// should disappear quickly as we add support for legalizing non-power-of-2 /// sized types further. -static void -addAndInterleaveWithUnsupported(LegalizerInfo::SizeAndActionsVec &result, - const LegalizerInfo::SizeAndActionsVec &v) { +static void addAndInterleaveWithUnsupported( + LegacyLegalizerInfo::SizeAndActionsVec &result, + const LegacyLegalizerInfo::SizeAndActionsVec &v) { for (unsigned i = 0; i < v.size(); ++i) { result.push_back(v[i]); if (i + 1 < v[i].first && i + 1 < v.size() && v[i + 1].first != v[i].first + 1) - result.push_back({v[i].first + 1, Unsupported}); + result.push_back({v[i].first + 1, LegacyLegalizeActions::Unsupported}); } } -static LegalizerInfo::SizeAndActionsVec -widen_8_16(const LegalizerInfo::SizeAndActionsVec &v) { +static LegacyLegalizerInfo::SizeAndActionsVec +widen_8_16(const LegacyLegalizerInfo::SizeAndActionsVec &v) { assert(v.size() >= 1); assert(v[0].first > 17); - LegalizerInfo::SizeAndActionsVec result = {{1, Unsupported}, - {8, WidenScalar}, - {9, Unsupported}, - {16, WidenScalar}, - {17, Unsupported}}; + LegacyLegalizerInfo::SizeAndActionsVec result = { + {1, LegacyLegalizeActions::Unsupported}, + {8, LegacyLegalizeActions::WidenScalar}, + {9, LegacyLegalizeActions::Unsupported}, + {16, LegacyLegalizeActions::WidenScalar}, + {17, LegacyLegalizeActions::Unsupported}}; addAndInterleaveWithUnsupported(result, v); auto Largest = result.back().first; - result.push_back({Largest + 1, Unsupported}); + result.push_back({Largest + 1, LegacyLegalizeActions::Unsupported}); return result; } @@ -74,9 +75,10 @@ const LLT s32 = LLT::scalar(32); const LLT s64 = LLT::scalar(64); + auto &LegacyInfo = getLegacyLegalizerInfo(); if (ST.isThumb1Only()) { // Thumb1 is not supported yet. - computeTables(); + LegacyInfo.computeTables(); verify(*ST.getInstrInfo()); return; } @@ -116,13 +118,13 @@ .clampScalar(0, s32, s32); for (unsigned Op : {G_SREM, G_UREM}) { - setLegalizeScalarToDifferentSizeStrategy(Op, 0, widen_8_16); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(Op, 0, widen_8_16); if (HasHWDivide) - setAction({Op, s32}, Lower); + LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Lower); else if (AEABI(ST)) - setAction({Op, s32}, Custom); + LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Custom); else - setAction({Op, s32}, Libcall); + LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Libcall); } getActionDefinitionsBuilder(G_INTTOPTR) @@ -198,7 +200,7 @@ LoadStoreBuilder.maxScalar(0, s32); for (auto Ty : {s32, s64}) - setAction({G_FNEG, Ty}, Lower); + LegacyInfo.setAction({G_FNEG, Ty}, LegacyLegalizeActions::Lower); getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64}); @@ -246,7 +248,7 @@ .clampScalar(0, s32, s32); } - computeTables(); + LegacyInfo.computeTables(); verify(*ST.getInstrInfo()); } diff --git a/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp b/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp --- a/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp +++ b/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp @@ -321,7 +321,7 @@ getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); - computeTables(); + getLegacyLegalizerInfo().computeTables(); verify(*ST.getInstrInfo()); } diff --git a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp @@ -17,4 +17,6 @@ using namespace llvm; using namespace LegalizeActions; -PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { computeTables(); } +PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { + getLegacyLegalizerInfo().computeTables(); +} diff --git a/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVLegalizerInfo.cpp @@ -19,5 +19,5 @@ using namespace llvm; RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) { - computeTables(); + getLegacyLegalizerInfo().computeTables(); } diff --git a/llvm/lib/Target/X86/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/X86LegalizerInfo.cpp --- a/llvm/lib/Target/X86/X86LegalizerInfo.cpp +++ b/llvm/lib/Target/X86/X86LegalizerInfo.cpp @@ -32,26 +32,27 @@ /// In practice, not specifying those isn't a problem, and the below functions /// should disappear quickly as we add support for legalizing non-power-of-2 /// sized types further. -static void -addAndInterleaveWithUnsupported(LegalizerInfo::SizeAndActionsVec &result, - const LegalizerInfo::SizeAndActionsVec &v) { +static void addAndInterleaveWithUnsupported( + LegacyLegalizerInfo::SizeAndActionsVec &result, + const LegacyLegalizerInfo::SizeAndActionsVec &v) { for (unsigned i = 0; i < v.size(); ++i) { result.push_back(v[i]); if (i + 1 < v[i].first && i + 1 < v.size() && v[i + 1].first != v[i].first + 1) - result.push_back({v[i].first + 1, Unsupported}); + result.push_back({v[i].first + 1, LegacyLegalizeActions::Unsupported}); } } -static LegalizerInfo::SizeAndActionsVec -widen_1(const LegalizerInfo::SizeAndActionsVec &v) { +static LegacyLegalizerInfo::SizeAndActionsVec +widen_1(const LegacyLegalizerInfo::SizeAndActionsVec &v) { assert(v.size() >= 1); assert(v[0].first > 1); - LegalizerInfo::SizeAndActionsVec result = {{1, WidenScalar}, - {2, Unsupported}}; + LegacyLegalizerInfo::SizeAndActionsVec result = { + {1, LegacyLegalizeActions::WidenScalar}, + {2, LegacyLegalizeActions::Unsupported}}; addAndInterleaveWithUnsupported(result, v); auto Largest = result.back().first; - result.push_back({Largest + 1, Unsupported}); + result.push_back({Largest + 1, LegacyLegalizeActions::Unsupported}); return result; } @@ -75,20 +76,23 @@ .minScalar(0, LLT::scalar(32)) .libcall(); - setLegalizeScalarToDifferentSizeStrategy(G_PHI, 0, widen_1); + auto &LegacyInfo = getLegacyLegalizerInfo(); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(G_PHI, 0, widen_1); for (unsigned BinOp : {G_SUB, G_MUL, G_AND, G_OR, G_XOR}) - setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, widen_1); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, widen_1); for (unsigned MemOp : {G_LOAD, G_STORE}) - setLegalizeScalarToDifferentSizeStrategy(MemOp, 0, - narrowToSmallerAndWidenToSmallest); - setLegalizeScalarToDifferentSizeStrategy( - G_PTR_ADD, 1, widenToLargerTypesUnsupportedOtherwise); - setLegalizeScalarToDifferentSizeStrategy( - G_CONSTANT, 0, widenToLargerTypesAndNarrowToLargest); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + MemOp, 0, LegacyLegalizerInfo::narrowToSmallerAndWidenToSmallest); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + G_PTR_ADD, 1, + LegacyLegalizerInfo::widenToLargerTypesUnsupportedOtherwise); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + G_CONSTANT, 0, + LegacyLegalizerInfo::widenToLargerTypesAndNarrowToLargest); getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); - computeTables(); + LegacyInfo.computeTables(); verify(*STI.getInstrInfo()); } @@ -107,35 +111,37 @@ const LLT s64 = LLT::scalar(64); const LLT s128 = LLT::scalar(128); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (auto Ty : {p0, s1, s8, s16, s32}) - setAction({G_IMPLICIT_DEF, Ty}, Legal); + LegacyInfo.setAction({G_IMPLICIT_DEF, Ty}, LegacyLegalizeActions::Legal); for (auto Ty : {s8, s16, s32, p0}) - setAction({G_PHI, Ty}, Legal); + LegacyInfo.setAction({G_PHI, Ty}, LegacyLegalizeActions::Legal); for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR}) for (auto Ty : {s8, s16, s32}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); for (unsigned Op : {G_UADDE}) { - setAction({Op, s32}, Legal); - setAction({Op, 1, s1}, Legal); + LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({Op, 1, s1}, LegacyLegalizeActions::Legal); } for (unsigned MemOp : {G_LOAD, G_STORE}) { for (auto Ty : {s8, s16, s32, p0}) - setAction({MemOp, Ty}, Legal); + LegacyInfo.setAction({MemOp, Ty}, LegacyLegalizeActions::Legal); // And everything's fine in addrspace 0. - setAction({MemOp, 1, p0}, Legal); + LegacyInfo.setAction({MemOp, 1, p0}, LegacyLegalizeActions::Legal); } // Pointer-handling - setAction({G_FRAME_INDEX, p0}, Legal); - setAction({G_GLOBAL_VALUE, p0}, Legal); + LegacyInfo.setAction({G_FRAME_INDEX, p0}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_GLOBAL_VALUE, p0}, LegacyLegalizeActions::Legal); - setAction({G_PTR_ADD, p0}, Legal); - setAction({G_PTR_ADD, 1, s32}, Legal); + LegacyInfo.setAction({G_PTR_ADD, p0}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_PTR_ADD, 1, s32}, LegacyLegalizeActions::Legal); if (!Subtarget.is64Bit()) { getActionDefinitionsBuilder(G_PTRTOINT) @@ -163,29 +169,31 @@ } // Control-flow - setAction({G_BRCOND, s1}, Legal); + LegacyInfo.setAction({G_BRCOND, s1}, LegacyLegalizeActions::Legal); // Constants for (auto Ty : {s8, s16, s32, p0}) - setAction({TargetOpcode::G_CONSTANT, Ty}, Legal); + LegacyInfo.setAction({TargetOpcode::G_CONSTANT, Ty}, + LegacyLegalizeActions::Legal); // Extensions for (auto Ty : {s8, s16, s32}) { - setAction({G_ZEXT, Ty}, Legal); - setAction({G_SEXT, Ty}, Legal); - setAction({G_ANYEXT, Ty}, Legal); + LegacyInfo.setAction({G_ZEXT, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_SEXT, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_ANYEXT, Ty}, LegacyLegalizeActions::Legal); } - setAction({G_ANYEXT, s128}, Legal); + LegacyInfo.setAction({G_ANYEXT, s128}, LegacyLegalizeActions::Legal); getActionDefinitionsBuilder(G_SEXT_INREG).lower(); // Merge/Unmerge for (const auto &Ty : {s16, s32, s64}) { - setAction({G_MERGE_VALUES, Ty}, Legal); - setAction({G_UNMERGE_VALUES, 1, Ty}, Legal); + LegacyInfo.setAction({G_MERGE_VALUES, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, 1, Ty}, + LegacyLegalizeActions::Legal); } for (const auto &Ty : {s8, s16, s32}) { - setAction({G_MERGE_VALUES, 1, Ty}, Legal); - setAction({G_UNMERGE_VALUES, Ty}, Legal); + LegacyInfo.setAction({G_MERGE_VALUES, 1, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, Ty}, LegacyLegalizeActions::Legal); } } @@ -202,21 +210,23 @@ const LLT s64 = LLT::scalar(64); const LLT s128 = LLT::scalar(128); - setAction({G_IMPLICIT_DEF, s64}, Legal); + auto &LegacyInfo = getLegacyLegalizerInfo(); + + LegacyInfo.setAction({G_IMPLICIT_DEF, s64}, LegacyLegalizeActions::Legal); // Need to have that, as tryFoldImplicitDef will create this pattern: // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF - setAction({G_IMPLICIT_DEF, s128}, Legal); + LegacyInfo.setAction({G_IMPLICIT_DEF, s128}, LegacyLegalizeActions::Legal); - setAction({G_PHI, s64}, Legal); + LegacyInfo.setAction({G_PHI, s64}, LegacyLegalizeActions::Legal); for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR}) - setAction({BinOp, s64}, Legal); + LegacyInfo.setAction({BinOp, s64}, LegacyLegalizeActions::Legal); for (unsigned MemOp : {G_LOAD, G_STORE}) - setAction({MemOp, s64}, Legal); + LegacyInfo.setAction({MemOp, s64}, LegacyLegalizeActions::Legal); // Pointer-handling - setAction({G_PTR_ADD, 1, s64}, Legal); + LegacyInfo.setAction({G_PTR_ADD, 1, s64}, LegacyLegalizeActions::Legal); getActionDefinitionsBuilder(G_PTRTOINT) .legalForCartesianProduct({s1, s8, s16, s32, s64}, {p0}) .maxScalar(0, s64) @@ -224,11 +234,12 @@ getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, s64}}); // Constants - setAction({TargetOpcode::G_CONSTANT, s64}, Legal); + LegacyInfo.setAction({TargetOpcode::G_CONSTANT, s64}, + LegacyLegalizeActions::Legal); // Extensions for (unsigned extOp : {G_ZEXT, G_SEXT, G_ANYEXT}) { - setAction({extOp, s64}, Legal); + LegacyInfo.setAction({extOp, s64}, LegacyLegalizeActions::Legal); } getActionDefinitionsBuilder(G_SITOFP) @@ -270,10 +281,11 @@ .clampScalar(1, s8, s8); // Merge/Unmerge - setAction({G_MERGE_VALUES, s128}, Legal); - setAction({G_UNMERGE_VALUES, 1, s128}, Legal); - setAction({G_MERGE_VALUES, 1, s128}, Legal); - setAction({G_UNMERGE_VALUES, s128}, Legal); + LegacyInfo.setAction({G_MERGE_VALUES, s128}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, 1, s128}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_MERGE_VALUES, 1, s128}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, s128}, LegacyLegalizeActions::Legal); } void X86LegalizerInfo::setLegalizerInfoSSE1() { @@ -285,24 +297,28 @@ const LLT v4s32 = LLT::vector(4, 32); const LLT v2s64 = LLT::vector(2, 64); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV}) for (auto Ty : {s32, v4s32}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); for (unsigned MemOp : {G_LOAD, G_STORE}) for (auto Ty : {v4s32, v2s64}) - setAction({MemOp, Ty}, Legal); + LegacyInfo.setAction({MemOp, Ty}, LegacyLegalizeActions::Legal); // Constants - setAction({TargetOpcode::G_FCONSTANT, s32}, Legal); + LegacyInfo.setAction({TargetOpcode::G_FCONSTANT, s32}, + LegacyLegalizeActions::Legal); // Merge/Unmerge for (const auto &Ty : {v4s32, v2s64}) { - setAction({G_CONCAT_VECTORS, Ty}, Legal); - setAction({G_UNMERGE_VALUES, 1, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, 1, Ty}, + LegacyLegalizeActions::Legal); } - setAction({G_MERGE_VALUES, 1, s64}, Legal); - setAction({G_UNMERGE_VALUES, s64}, Legal); + LegacyInfo.setAction({G_MERGE_VALUES, 1, s64}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, s64}, LegacyLegalizeActions::Legal); } void X86LegalizerInfo::setLegalizerInfoSSE2() { @@ -321,34 +337,39 @@ const LLT v8s32 = LLT::vector(8, 32); const LLT v4s64 = LLT::vector(4, 64); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV}) for (auto Ty : {s64, v2s64}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); for (unsigned BinOp : {G_ADD, G_SUB}) for (auto Ty : {v16s8, v8s16, v4s32, v2s64}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); - setAction({G_MUL, v8s16}, Legal); + LegacyInfo.setAction({G_MUL, v8s16}, LegacyLegalizeActions::Legal); - setAction({G_FPEXT, s64}, Legal); - setAction({G_FPEXT, 1, s32}, Legal); + LegacyInfo.setAction({G_FPEXT, s64}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_FPEXT, 1, s32}, LegacyLegalizeActions::Legal); - setAction({G_FPTRUNC, s32}, Legal); - setAction({G_FPTRUNC, 1, s64}, Legal); + LegacyInfo.setAction({G_FPTRUNC, s32}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_FPTRUNC, 1, s64}, LegacyLegalizeActions::Legal); // Constants - setAction({TargetOpcode::G_FCONSTANT, s64}, Legal); + LegacyInfo.setAction({TargetOpcode::G_FCONSTANT, s64}, + LegacyLegalizeActions::Legal); // Merge/Unmerge for (const auto &Ty : {v16s8, v32s8, v8s16, v16s16, v4s32, v8s32, v2s64, v4s64}) { - setAction({G_CONCAT_VECTORS, Ty}, Legal); - setAction({G_UNMERGE_VALUES, 1, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, 1, Ty}, + LegacyLegalizeActions::Legal); } for (const auto &Ty : {v16s8, v8s16, v4s32, v2s64}) { - setAction({G_CONCAT_VECTORS, 1, Ty}, Legal); - setAction({G_UNMERGE_VALUES, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, 1, Ty}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, Ty}, LegacyLegalizeActions::Legal); } } @@ -358,7 +379,9 @@ const LLT v4s32 = LLT::vector(4, 32); - setAction({G_MUL, v4s32}, Legal); + auto &LegacyInfo = getLegacyLegalizerInfo(); + + LegacyInfo.setAction({G_MUL, v4s32}, LegacyLegalizeActions::Legal); } void X86LegalizerInfo::setLegalizerInfoAVX() { @@ -379,28 +402,32 @@ const LLT v4s64 = LLT::vector(4, 64); const LLT v8s64 = LLT::vector(8, 64); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (unsigned MemOp : {G_LOAD, G_STORE}) for (auto Ty : {v8s32, v4s64}) - setAction({MemOp, Ty}, Legal); + LegacyInfo.setAction({MemOp, Ty}, LegacyLegalizeActions::Legal); for (auto Ty : {v32s8, v16s16, v8s32, v4s64}) { - setAction({G_INSERT, Ty}, Legal); - setAction({G_EXTRACT, 1, Ty}, Legal); + LegacyInfo.setAction({G_INSERT, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_EXTRACT, 1, Ty}, LegacyLegalizeActions::Legal); } for (auto Ty : {v16s8, v8s16, v4s32, v2s64}) { - setAction({G_INSERT, 1, Ty}, Legal); - setAction({G_EXTRACT, Ty}, Legal); + LegacyInfo.setAction({G_INSERT, 1, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_EXTRACT, Ty}, LegacyLegalizeActions::Legal); } // Merge/Unmerge for (const auto &Ty : {v32s8, v64s8, v16s16, v32s16, v8s32, v16s32, v4s64, v8s64}) { - setAction({G_CONCAT_VECTORS, Ty}, Legal); - setAction({G_UNMERGE_VALUES, 1, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, 1, Ty}, + LegacyLegalizeActions::Legal); } for (const auto &Ty : {v16s8, v32s8, v8s16, v16s16, v4s32, v8s32, v2s64, v4s64}) { - setAction({G_CONCAT_VECTORS, 1, Ty}, Legal); - setAction({G_UNMERGE_VALUES, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, 1, Ty}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, Ty}, LegacyLegalizeActions::Legal); } } @@ -418,21 +445,25 @@ const LLT v16s32 = LLT::vector(16, 32); const LLT v8s64 = LLT::vector(8, 64); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (unsigned BinOp : {G_ADD, G_SUB}) for (auto Ty : {v32s8, v16s16, v8s32, v4s64}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); for (auto Ty : {v16s16, v8s32}) - setAction({G_MUL, Ty}, Legal); + LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal); // Merge/Unmerge for (const auto &Ty : {v64s8, v32s16, v16s32, v8s64}) { - setAction({G_CONCAT_VECTORS, Ty}, Legal); - setAction({G_UNMERGE_VALUES, 1, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, 1, Ty}, + LegacyLegalizeActions::Legal); } for (const auto &Ty : {v32s8, v16s16, v8s32, v4s64}) { - setAction({G_CONCAT_VECTORS, 1, Ty}, Legal); - setAction({G_UNMERGE_VALUES, Ty}, Legal); + LegacyInfo.setAction({G_CONCAT_VECTORS, 1, Ty}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_UNMERGE_VALUES, Ty}, LegacyLegalizeActions::Legal); } } @@ -455,23 +486,25 @@ const LLT v16s32 = LLT::vector(16, 32); const LLT v8s64 = LLT::vector(8, 64); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (unsigned BinOp : {G_ADD, G_SUB}) for (auto Ty : {v16s32, v8s64}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); - setAction({G_MUL, v16s32}, Legal); + LegacyInfo.setAction({G_MUL, v16s32}, LegacyLegalizeActions::Legal); for (unsigned MemOp : {G_LOAD, G_STORE}) for (auto Ty : {v16s32, v8s64}) - setAction({MemOp, Ty}, Legal); + LegacyInfo.setAction({MemOp, Ty}, LegacyLegalizeActions::Legal); for (auto Ty : {v64s8, v32s16, v16s32, v8s64}) { - setAction({G_INSERT, Ty}, Legal); - setAction({G_EXTRACT, 1, Ty}, Legal); + LegacyInfo.setAction({G_INSERT, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_EXTRACT, 1, Ty}, LegacyLegalizeActions::Legal); } for (auto Ty : {v32s8, v16s16, v8s32, v4s64, v16s8, v8s16, v4s32, v2s64}) { - setAction({G_INSERT, 1, Ty}, Legal); - setAction({G_EXTRACT, Ty}, Legal); + LegacyInfo.setAction({G_INSERT, 1, Ty}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_EXTRACT, Ty}, LegacyLegalizeActions::Legal); } /************ VLX *******************/ @@ -479,7 +512,7 @@ return; for (auto Ty : {v4s32, v8s32}) - setAction({G_MUL, Ty}, Legal); + LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal); } void X86LegalizerInfo::setLegalizerInfoAVX512DQ() { @@ -488,7 +521,9 @@ const LLT v8s64 = LLT::vector(8, 64); - setAction({G_MUL, v8s64}, Legal); + auto &LegacyInfo = getLegacyLegalizerInfo(); + + LegacyInfo.setAction({G_MUL, v8s64}, LegacyLegalizeActions::Legal); /************ VLX *******************/ if (!Subtarget.hasVLX()) @@ -498,7 +533,7 @@ const LLT v4s64 = LLT::vector(4, 64); for (auto Ty : {v2s64, v4s64}) - setAction({G_MUL, Ty}, Legal); + LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal); } void X86LegalizerInfo::setLegalizerInfoAVX512BW() { @@ -508,11 +543,13 @@ const LLT v64s8 = LLT::vector(64, 8); const LLT v32s16 = LLT::vector(32, 16); + auto &LegacyInfo = getLegacyLegalizerInfo(); + for (unsigned BinOp : {G_ADD, G_SUB}) for (auto Ty : {v64s8, v32s16}) - setAction({BinOp, Ty}, Legal); + LegacyInfo.setAction({BinOp, Ty}, LegacyLegalizeActions::Legal); - setAction({G_MUL, v32s16}, Legal); + LegacyInfo.setAction({G_MUL, v32s16}, LegacyLegalizeActions::Legal); /************ VLX *******************/ if (!Subtarget.hasVLX()) @@ -522,5 +559,5 @@ const LLT v16s16 = LLT::vector(16, 16); for (auto Ty : {v8s16, v16s16}) - setAction({G_MUL, Ty}, Legal); + LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal); } diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -169,7 +169,7 @@ (void)s128; \ do \ SettingUpActionsBlock while (0); \ - computeTables(); \ + getLegacyLegalizerInfo().computeTables(); \ verify(*ST.getInstrInfo()); \ } \ }; diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -1409,7 +1409,7 @@ LI.getActionDefinitionsBuilder(TargetOpcode::G_AND) .legalFor({v6s32}) .clampMinNumElements(0, s32, 6); - LI.computeTables(); + LI.getLegacyLegalizerInfo().computeTables(); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, LI, Observer, B); @@ -1454,7 +1454,7 @@ LI.getActionDefinitionsBuilder(TargetOpcode::G_PHI) .legalFor({v2s32}) .clampMinNumElements(0, s32, 2); - LI.computeTables(); + LI.getLegacyLegalizerInfo().computeTables(); LLT PhiTy = v5s32; DummyGISelObserver Observer; diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp @@ -48,15 +48,17 @@ TEST(LegalizerInfoTest, ScalarRISC) { using namespace TargetOpcode; LegalizerInfo L; + auto &LegacyInfo = L.getLegacyLegalizerInfo(); // Typical RISCy set of operations based on AArch64. for (unsigned Op : {G_ADD, G_SUB}) { for (unsigned Size : {32, 64}) - L.setAction({Op, 0, LLT::scalar(Size)}, Legal); - L.setLegalizeScalarToDifferentSizeStrategy( - Op, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest); + LegacyInfo.setAction({Op, 0, LLT::scalar(Size)}, + LegacyLegalizeActions::Legal); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + Op, 0, LegacyLegalizerInfo::widenToLargerTypesAndNarrowToLargest); } - L.computeTables(); + LegacyInfo.computeTables(); for (unsigned opcode : {G_ADD, G_SUB}) { // Check we infer the correct types and actually do what we're told. @@ -89,20 +91,28 @@ TEST(LegalizerInfoTest, VectorRISC) { using namespace TargetOpcode; LegalizerInfo L; + auto &LegacyInfo = L.getLegacyLegalizerInfo(); // Typical RISCy set of operations based on ARM. - L.setAction({G_ADD, LLT::vector(8, 8)}, Legal); - L.setAction({G_ADD, LLT::vector(16, 8)}, Legal); - L.setAction({G_ADD, LLT::vector(4, 16)}, Legal); - L.setAction({G_ADD, LLT::vector(8, 16)}, Legal); - L.setAction({G_ADD, LLT::vector(2, 32)}, Legal); - L.setAction({G_ADD, LLT::vector(4, 32)}, Legal); - - L.setLegalizeVectorElementToDifferentSizeStrategy( - G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); - - L.setAction({G_ADD, 0, LLT::scalar(32)}, Legal); - - L.computeTables(); + LegacyInfo.setAction({G_ADD, LLT::vector(8, 8)}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_ADD, LLT::vector(16, 8)}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_ADD, LLT::vector(4, 16)}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_ADD, LLT::vector(8, 16)}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_ADD, LLT::vector(2, 32)}, + LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_ADD, LLT::vector(4, 32)}, + LegacyLegalizeActions::Legal); + + LegacyInfo.setLegalizeVectorElementToDifferentSizeStrategy( + G_ADD, 0, LegacyLegalizerInfo::widenToLargerTypesUnsupportedOtherwise); + + LegacyInfo.setAction({G_ADD, 0, LLT::scalar(32)}, + LegacyLegalizeActions::Legal); + + LegacyInfo.computeTables(); // Check we infer the correct types and actually do what we're told for some // simple cases. @@ -124,17 +134,18 @@ TEST(LegalizerInfoTest, MultipleTypes) { using namespace TargetOpcode; LegalizerInfo L; + auto &LegacyInfo = L.getLegacyLegalizerInfo(); LLT p0 = LLT::pointer(0, 64); LLT s64 = LLT::scalar(64); // Typical RISCy set of operations based on AArch64. - L.setAction({G_PTRTOINT, 0, s64}, Legal); - L.setAction({G_PTRTOINT, 1, p0}, Legal); + LegacyInfo.setAction({G_PTRTOINT, 0, s64}, LegacyLegalizeActions::Legal); + LegacyInfo.setAction({G_PTRTOINT, 1, p0}, LegacyLegalizeActions::Legal); - L.setLegalizeScalarToDifferentSizeStrategy( - G_PTRTOINT, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + G_PTRTOINT, 0, LegacyLegalizerInfo::widenToLargerTypesAndNarrowToLargest); - L.computeTables(); + LegacyInfo.computeTables(); // Check we infer the correct types and actually do what we're told. EXPECT_EQ(L.getAction({G_PTRTOINT, {s64, p0}}), @@ -152,15 +163,16 @@ TEST(LegalizerInfoTest, MultipleSteps) { using namespace TargetOpcode; LegalizerInfo L; + auto &LegacyInfo = L.getLegacyLegalizerInfo(); LLT s32 = LLT::scalar(32); LLT s64 = LLT::scalar(64); - L.setLegalizeScalarToDifferentSizeStrategy( - G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); - L.setAction({G_UREM, 0, s32}, Lower); - L.setAction({G_UREM, 0, s64}, Lower); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + G_UREM, 0, LegacyLegalizerInfo::widenToLargerTypesUnsupportedOtherwise); + LegacyInfo.setAction({G_UREM, 0, s32}, LegacyLegalizeActions::Lower); + LegacyInfo.setAction({G_UREM, 0, s64}, LegacyLegalizeActions::Lower); - L.computeTables(); + LegacyInfo.computeTables(); EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(16)}}), LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); @@ -171,12 +183,14 @@ TEST(LegalizerInfoTest, SizeChangeStrategy) { using namespace TargetOpcode; LegalizerInfo L; + auto &LegacyInfo = L.getLegacyLegalizerInfo(); for (unsigned Size : {1, 8, 16, 32}) - L.setAction({G_UREM, 0, LLT::scalar(Size)}, Legal); + LegacyInfo.setAction({G_UREM, 0, LLT::scalar(Size)}, + LegacyLegalizeActions::Legal); - L.setLegalizeScalarToDifferentSizeStrategy( - G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); - L.computeTables(); + LegacyInfo.setLegalizeScalarToDifferentSizeStrategy( + G_UREM, 0, LegacyLegalizerInfo::widenToLargerTypesUnsupportedOtherwise); + LegacyInfo.computeTables(); // Check we infer the correct types and actually do what we're told. for (unsigned Size : {1, 8, 16, 32}) { @@ -229,11 +243,12 @@ { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_IMPLICIT_DEF) .legalFor({v4s32, v4p0}) .moreElementsToNextPow2(0); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {s32})); EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {v2s32})); @@ -244,10 +259,11 @@ // Test minScalarOrElt { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_OR) .legalFor({s32}) .minScalarOrElt(0, s32); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16})); EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_OR, {v2s16})); @@ -256,10 +272,11 @@ // Test maxScalarOrELt { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_AND) .legalFor({s16}) .maxScalarOrElt(0, s16); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32})); EXPECT_ACTION(NarrowScalar, 0, v2s16, LegalityQuery(G_AND, {v2s32})); @@ -268,10 +285,11 @@ // Test clampScalarOrElt { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_XOR) .legalFor({s16}) .clampScalarOrElt(0, s16, s32); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64})); EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8})); @@ -284,10 +302,11 @@ // Test minScalar { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_OR) .legalFor({s32}) .minScalar(0, s32); - LI.computeTables(); + LegacyInfo.computeTables(); // Only handle scalars, ignore vectors. EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16})); @@ -297,10 +316,11 @@ // Test maxScalar { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_AND) .legalFor({s16}) .maxScalar(0, s16); - LI.computeTables(); + LegacyInfo.computeTables(); // Only handle scalars, ignore vectors. EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32})); @@ -310,11 +330,12 @@ // Test clampScalar { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_XOR) .legalFor({s16}) .clampScalar(0, s16, s32); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64})); EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8})); @@ -327,11 +348,12 @@ // Test widenScalarOrEltToNextPow2 { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_AND) .legalFor({s32}) .widenScalarOrEltToNextPow2(0, 32); - LI.computeTables(); + LegacyInfo.computeTables(); // Handle scalars and vectors EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5})); @@ -343,11 +365,12 @@ // Test widenScalarToNextPow2 { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_AND) .legalFor({s32}) .widenScalarToNextPow2(0, 32); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5})); EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33})); @@ -366,10 +389,11 @@ { LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_LOAD) .legalForTypesWithMemDesc({{s32, p0, 32, 32}}); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(Legal, 0, LLT(), LegalityQuery(G_LOAD, {s32, p0}, @@ -391,10 +415,11 @@ const uint64_t MaxAlignment = UINT64_C(1) << 29; const uint64_t MaxAlignInBits = 8 * MaxAlignment; LegalizerInfo LI; + auto &LegacyInfo = LI.getLegacyLegalizerInfo(); LI.getActionDefinitionsBuilder(G_LOAD) .legalForTypesWithMemDesc({{s32, p0, 32, MaxAlignInBits}}); - LI.computeTables(); + LegacyInfo.computeTables(); EXPECT_ACTION(Legal, 0, LLT(), LegalityQuery(G_LOAD, {s32, p0},