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:
parent
b0a805b25d
commit
71a22fb7f8
479
include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
Normal file
479
include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
Normal 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
|
@ -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
|
||||
|
@ -16,6 +16,7 @@ add_llvm_component_library(LLVMGlobalISel
|
||||
Legalizer.cpp
|
||||
LegalizerHelper.cpp
|
||||
LegalizerInfo.cpp
|
||||
LegacyLegalizerInfo.cpp
|
||||
Localizer.cpp
|
||||
LostDebugLocObserver.cpp
|
||||
MachineIRBuilder.cpp
|
||||
|
344
lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp
Normal file
344
lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp
Normal 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{}};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -321,7 +321,7 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
|
||||
|
||||
getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
|
||||
|
||||
computeTables();
|
||||
getLegacyLegalizerInfo().computeTables();
|
||||
verify(*ST.getInstrInfo());
|
||||
}
|
||||
|
||||
|
@ -17,4 +17,6 @@
|
||||
using namespace llvm;
|
||||
using namespace LegalizeActions;
|
||||
|
||||
PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { computeTables(); }
|
||||
PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) {
|
||||
getLegacyLegalizerInfo().computeTables();
|
||||
}
|
||||
|
@ -19,5 +19,5 @@
|
||||
using namespace llvm;
|
||||
|
||||
RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
|
||||
computeTables();
|
||||
getLegacyLegalizerInfo().computeTables();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ class AMDGPUGISelMITest : public GISelMITest {
|
||||
(void)s128; \
|
||||
do \
|
||||
SettingUpActionsBlock while (0); \
|
||||
computeTables(); \
|
||||
getLegacyLegalizerInfo().computeTables(); \
|
||||
verify(*ST.getInstrInfo()); \
|
||||
} \
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user