1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
|
//===- llvm/CodeGen/GlobalISel/LegalizerInfo.h ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// Interface for Targets to specify which operations they can successfully
/// select and how the others should be expanded most efficiently.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
#define LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/Support/LowLevelTypeImpl.h"
#include <cassert>
#include <cstdint>
#include <tuple>
#include <unordered_map>
#include <utility>
namespace llvm {
class MachineInstr;
class MachineIRBuilder;
class MachineRegisterInfo;
/// 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;
}
};
class LegalizerInfo {
public:
enum LegalizeAction : 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,
/// 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,
};
LegalizerInfo();
virtual ~LegalizerInfo() = default;
/// 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();
static bool needsLegalizingToDifferentSize(const LegalizeAction Action) {
switch (Action) {
case NarrowScalar:
case WidenScalar:
case FewerElements:
case MoreElements:
case Unsupported:
return true;
default:
return false;
}
}
typedef std::pair<uint16_t, LegalizeAction> SizeAndAction;
typedef std::vector<SizeAndAction> SizeAndActionsVec;
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) {
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) {
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) {
return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
Unsupported);
}
static SizeAndActionsVec
narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) {
return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
Unsupported);
}
static SizeAndActionsVec
narrowToSmallerAndWidenToSmallest(const SizeAndActionsVec &v) {
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) {
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);
/// 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> getAction(const InstrAspect &Aspect) const;
/// Determine what action should be taken to legalize the given generic
/// instruction.
///
/// \returns a tuple consisting of the LegalizeAction that should be
/// performed, the type-index it should be performed on and the destination
/// type.
std::tuple<LegalizeAction, unsigned, LLT>
getAction(const MachineInstr &MI, const MachineRegisterInfo &MRI) const;
bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const;
virtual bool legalizeCustom(MachineInstr &MI,
MachineRegisterInfo &MRI,
MachineIRBuilder &MIRBuilder) const;
private:
/// 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_GEP, 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) {
#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:
typedef DenseMap<LLT, LegalizeAction> TypeMap;
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 // LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
|