1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00

[globalisel][legalizer] Separate the deprecated LegalizerInfo from the current one

It's still in use in a few places so we can't delete it yet but there's not
many at this point.

Differential Revision: https://reviews.llvm.org/D103352
This commit is contained in:
Daniel Sanders 2021-05-28 19:36:56 -07:00
parent b0a805b25d
commit 71a22fb7f8
15 changed files with 1111 additions and 845 deletions

View File

@ -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 <unordered_map>
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<uint16_t, LegacyLegalizeActions::LegacyLegalizeAction>;
using SizeAndActionsVec = std::vector<SizeAndAction>;
using SizeChangeStrategy =
std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>;
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<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
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<SizeAndActionsVec, 1> &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<SizeAndActionsVec, 1> &Actions =
AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second;
setActions(TypeIndex, Actions, SizeAndActions);
}
/// If an operation on a given vector type (say <M x iN>) 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<SizeAndActionsVec, 1> &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<SizeAndActionsVec, 1> &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<v.size(); ++i) {
switch (v[i].second) {
case FewerElements:
case NarrowScalar:
if (SmallestNarrowIdx == -1)
SmallestNarrowIdx = i;
break;
case WidenScalar:
case MoreElements:
LargestWidenIdx = i;
break;
case Unsupported:
break;
default:
if (SmallestLegalizableToSameSizeIdx == -1)
SmallestLegalizableToSameSizeIdx = i;
LargestLegalizableToSameSizeIdx = i;
}
}
if (SmallestNarrowIdx != -1) {
assert(SmallestLegalizableToSameSizeIdx != -1);
assert(SmallestNarrowIdx > 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<SizeAndActionsVec, 1> &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<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
findScalarLegalAction(const InstrAspect &Aspect) const;
/// Returns the next action needed towards legalizing the vector type.
std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
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<LLT, LegacyLegalizeActions::LegacyLegalizeAction>;
SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];
SmallVector<SizeChangeStrategy, 1>
ScalarSizeChangeStrategies[LastOp - FirstOp + 1];
SmallVector<SizeChangeStrategy, 1>
VectorElementSizeChangeStrategies[LastOp - FirstOp + 1];
bool TablesInitialized;
// Data structures used by getAction:
SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
AddrSpace2PointerActions[LastOp - FirstOp + 1];
std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
NumElements2Actions[LastOp - FirstOp + 1];
};
} // end namespace llvm
#endif // define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H

View File

@ -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 @@ raw_ostream &operator<<(raw_ostream &OS, LegalizeActions::LegalizeAction Action)
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 @@ struct LegalizeActionStep {
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 @@ public:
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<uint16_t, LegalizeAction>;
using SizeAndActionsVec = std::vector<SizeAndAction>;
using SizeChangeStrategy =
std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>;
/// 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 @@ public:
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<LegalizeAction, LLT>
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<SizeAndActionsVec, 1> &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<SizeAndActionsVec, 1> &Actions =
AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second;
setActions(TypeIndex, Actions, SizeAndActions);
}
/// If an operation on a given vector type (say <M x iN>) 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<SizeAndActionsVec, 1> &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<SizeAndActionsVec, 1> &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<v.size(); ++i) {
switch (v[i].second) {
case FewerElements:
case NarrowScalar:
if (SmallestNarrowIdx == -1)
SmallestNarrowIdx = i;
break;
case WidenScalar:
case MoreElements:
LargestWidenIdx = i;
break;
case Unsupported:
break;
default:
if (SmallestLegalizableToSameSizeIdx == -1)
SmallestLegalizableToSameSizeIdx = i;
LargestLegalizableToSameSizeIdx = i;
}
}
if (SmallestNarrowIdx != -1) {
assert(SmallestLegalizableToSameSizeIdx != -1);
assert(SmallestNarrowIdx > 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<SizeAndActionsVec, 1> &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<LegalizeAction, LLT>
findScalarLegalAction(const InstrAspect &Aspect) const;
/// Returns the next action needed towards legalizing the vector type.
std::pair<LegalizeAction, LLT>
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<LLT, LegalizeAction>;
SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];
SmallVector<SizeChangeStrategy, 1>
ScalarSizeChangeStrategies[LastOp - FirstOp + 1];
SmallVector<SizeChangeStrategy, 1>
VectorElementSizeChangeStrategies[LastOp - FirstOp + 1];
bool TablesInitialized;
// Data structures used by getAction:
SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
AddrSpace2PointerActions[LastOp - FirstOp + 1];
std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
NumElements2Actions[LastOp - FirstOp + 1];
LegalizeRuleSet RulesForOpcode[LastOp - FirstOp + 1];
LegacyLegalizerInfo LegacyInfo;
};
#ifndef NDEBUG

View File

@ -16,6 +16,7 @@ add_llvm_component_library(LLVMGlobalISel
Legalizer.cpp
LegalizerHelper.cpp
LegalizerInfo.cpp
LegacyLegalizerInfo.cpp
Localizer.cpp
LostDebugLocObserver.cpp
MachineIRBuilder.cpp

View File

@ -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 <map>
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<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions;
// For vector types:
std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions;
for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) {
const LLT Type = LLT2Action.first;
const 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<LegacyLegalizeAction, LLT>
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<LegacyLegalizeAction, LLT>
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<SizeAndActionsVec, 1> &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<LegacyLegalizeAction, LLT>
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{}};
}

View File

@ -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 @@ bool LegalizeRuleSet::verifyImmIdxsCoverage(unsigned NumImmIdxs) const {
#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<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions;
// For vector types:
std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions;
for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) {
const LLT Type = LLT2Action.first;
const LegalizeAction Action = LLT2Action.second;
auto SizeAction = std::make_pair(Type.getSizeInBits(), Action);
if (Type.isPointer())
AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back(
SizeAction);
else if (Type.isVector())
ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()]
.push_back(SizeAction);
else
ScalarSpecifiedActions.push_back(SizeAction);
}
// 1. Handle scalar types
{
// Decide how to handle bit sizes for which no explicit specification
// was given.
SizeChangeStrategy S = &unsupportedForDifferentSizes;
if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() &&
ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx];
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<LegalizeAction, LLT>
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 @@ LegalizerInfo::getAction(const LegalityQuery &Query) const {
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 @@ bool LegalizerInfo::isLegalOrCustom(const MachineInstr &MI,
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<LegalizeAction, LLT>
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<SizeAndActionsVec, 1> &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<LegalizeAction, LLT>
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;
}

View File

@ -69,7 +69,7 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
// FIXME: support subtargets which have neon/fp-armv8 disabled.
if (!ST.hasNEON() || !ST.hasFPARMv8()) {
computeTables();
getLegacyLegalizerInfo().computeTables();
return;
}
@ -751,7 +751,7 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.maxScalarEltSameAsIf(always, 1, 0)
.customFor({{s32, s32}, {s64, s64}});
computeTables();
getLegacyLegalizerInfo().computeTables();
verify(*ST.getInstrInfo());
}

View File

@ -501,8 +501,11 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
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 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
.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 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
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 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
G_INDEXED_ZEXTLOAD, G_INDEXED_STORE})
.unsupported();
computeTables();
getLegacyLegalizerInfo().computeTables();
verify(*ST.getInstrInfo());
}

View File

@ -33,29 +33,30 @@ using namespace LegalizeActions;
/// 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 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
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 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
.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 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
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 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
.clampScalar(0, s32, s32);
}
computeTables();
LegacyInfo.computeTables();
verify(*ST.getInstrInfo());
}

View File

@ -321,7 +321,7 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
computeTables();
getLegacyLegalizerInfo().computeTables();
verify(*ST.getInstrInfo());
}

View File

@ -17,4 +17,6 @@
using namespace llvm;
using namespace LegalizeActions;
PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { computeTables(); }
PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) {
getLegacyLegalizerInfo().computeTables();
}

View File

@ -19,5 +19,5 @@
using namespace llvm;
RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
computeTables();
getLegacyLegalizerInfo().computeTables();
}

View File

@ -32,26 +32,27 @@ using namespace LegalizeActions;
/// 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 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
.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 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
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 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
}
// 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 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
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 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
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 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
.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 @@ void X86LegalizerInfo::setLegalizerInfoSSE1() {
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 @@ void X86LegalizerInfo::setLegalizerInfoSSE2() {
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 @@ void X86LegalizerInfo::setLegalizerInfoSSE41() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX2() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX512() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX512() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX512DQ() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX512DQ() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX512BW() {
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 @@ void X86LegalizerInfo::setLegalizerInfoAVX512BW() {
const LLT v16s16 = LLT::vector(16, 16);
for (auto Ty : {v8s16, v16s16})
setAction({G_MUL, Ty}, Legal);
LegacyInfo.setAction({G_MUL, Ty}, LegacyLegalizeActions::Legal);
}

View File

@ -169,7 +169,7 @@ class AMDGPUGISelMITest : public GISelMITest {
(void)s128; \
do \
SettingUpActionsBlock while (0); \
computeTables(); \
getLegacyLegalizerInfo().computeTables(); \
verify(*ST.getInstrInfo()); \
} \
};

View File

@ -1409,7 +1409,7 @@ TEST_F(AArch64GISelMITest, MoreElementsAnd) {
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 @@ TEST_F(AArch64GISelMITest, FewerElementsPhi) {
LI.getActionDefinitionsBuilder(TargetOpcode::G_PHI)
.legalFor({v2s32})
.clampMinNumElements(0, s32, 2);
LI.computeTables();
LI.getLegacyLegalizerInfo().computeTables();
LLT PhiTy = v5s32;
DummyGISelObserver Observer;

View File

@ -48,15 +48,17 @@ namespace {
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, ScalarRISC) {
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);
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);
L.setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
LegacyInfo.setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, LegacyLegalizerInfo::widenToLargerTypesUnsupportedOtherwise);
L.setAction({G_ADD, 0, LLT::scalar(32)}, Legal);
LegacyInfo.setAction({G_ADD, 0, LLT::scalar(32)},
LegacyLegalizeActions::Legal);
L.computeTables();
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, VectorRISC) {
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, MultipleTypes) {
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, MultipleSteps) {
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 @@ TEST(LegalizerInfoTest, RuleSets) {
{
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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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(LegalizerInfoTest, RuleSets) {
// 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 @@ TEST(LegalizerInfoTest, MMOAlignment) {
{
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 @@ TEST(LegalizerInfoTest, MMOAlignment) {
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},