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
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
//
// This file declares a class to access a table of extra information about the
// llvm.genx.* intrinsics, used by the vISA register allocator and function
// writer to decide exactly what operand type to use. The more usual approach
// in an LLVM target is to have an intrinsic map to an instruction in
// instruction selection, then have register category information on the
// instruction. But we are not using the target independent code generator, we
// are generating code directly from LLVM IR.
//
//===----------------------------------------------------------------------===//
#ifndef GENXINTRINSICS_H
#define GENXINTRINSICS_H
#include "GenX.h"
#include "GenXVisa.h"
#include "Probe/Assertion.h"
#include <unordered_map>
#define GENX_ITR_CATVAL(v) ((v) << CATBASE)
#define GENX_ITR_FLAGENUM(o, v) ((v) << ((o) + FLAGBASE))
#define GENX_ITR_FLAGMASK(o, w) (((1 << (w)) - 1) << ((o) + FLAGBASE))
#define GENX_ITR_FLAGVAL(o) GENX_ITR_FLAGENUM(o, 1)
namespace llvm {
class CallInst;
class GenXIntrinsicInfo {
public:
enum {
// General format of intrinsic descriptor words:
// Bits 31..24: Category enumeration
// Bits 23..8: Flags, if any, meaning and layout depends on category
// Bits 7..0: Operand or literal, if any
//
// One exception to the above is LITERAL, where everything that isn't
// the category field is assumed to be the literal value.
//
// If you want to re-apportion space in the descriptor word (typically
// because you need another flag and you can't express what you need to
// do without creating one) then just modify FLAGBASE and FLAGWIDTH
// below, and everything else will shake itself out appropriately.
// Currently 8 bits are allocated for the category enumaration bitfield,
// although the actual enumeration values defined only require 6 bits -
// and there is still plenty of space left over even within that.
// Similarly, there are 8 bits allocated to the operand bitfield, and
// currently the maximum needed is 5.
//
// At the moment, the GENERAL category has 4 unused flag bits available
// to it, the RAW category has 13 unused bits, and the ARGCOUNT category
// has 13 unused bits. No other categories make use of the flags yet,
// so it should be a good while yet before it's necessary to resize
// the bitfields.
FLAGBASE = 8,
FLAGWIDTH = 16,
CATBASE = FLAGBASE + FLAGWIDTH,
CATMASK = ~((1 << CATBASE) - 1),
FLAGMASK = ((~((1 << FLAGBASE) - 1)) ^ CATMASK),
OPNDMASK = ~(CATMASK | FLAGMASK),
// A field that does not contain an operand number or literal value:
IMPLICITPRED = GENX_ITR_CATVAL(0x01), // implicit predication field
NULLRAW = GENX_ITR_CATVAL(0x02), // null raw operand
ISBARRIER = GENX_ITR_CATVAL(0x03), // intrinsic is barrier: suppress nobarrier attribute
EXECSIZE = GENX_ITR_CATVAL(0x04), // execution size
EXECSIZE_GE2 = GENX_ITR_CATVAL(0x05), // execution size (must be >= 2)
EXECSIZE_GE4 = GENX_ITR_CATVAL(0x06), // execution size (must be >= 4)
EXECSIZE_GE8 = GENX_ITR_CATVAL(0x07), // execution size (must be >= 8)
EXECSIZE_NOT2 = GENX_ITR_CATVAL(0x08), // execution size (cannot be 2)
ELEMENTWISE = GENX_ITR_CATVAL(0x09), // intrinsic has element-wise semantics
// A field that contains a literal value the operand field
LITERAL = GENX_ITR_CATVAL(0x0a), // literal byte (usually opcode)
LITMASK = ~CATMASK,
// A field that contains an operand number, other than general:
FIRST_OPERAND = GENX_ITR_CATVAL(0x10),
LOG2OWORDS = GENX_ITR_CATVAL(0x10), // log2 number of owords
NUMGRFS = GENX_ITR_CATVAL(0x11), // rounded up number of GRFs
EXECSIZE_FROM_ARG = GENX_ITR_CATVAL(0x12), // exec_size field inferred from width of
// predication arg
SVMGATHERBLOCKSIZE = GENX_ITR_CATVAL(0x13), // svm gather block size, inferred from data type
LOG2OWORDS_PLUS_8 = GENX_ITR_CATVAL(0x14), // log2 number of owords, plus 8
GATHERNUMELTS = GENX_ITR_CATVAL(0x15), // gather/scatter "num elements" field
TRANSPOSEHEIGHT = GENX_ITR_CATVAL(0x16), // block_height field in transpose
LOG2ELTSIZE = GENX_ITR_CATVAL(0x17), // log2 element size in gather/scatter
ARGCOUNT = GENX_ITR_CATVAL(0x18), // Byte containing number of non-undef operands
EXECSIZE_FROM_BYTE = GENX_ITR_CATVAL(0x19), // exec_size specified in byte
ARGCOUNTMASK = GENX_ITR_FLAGMASK(0, 3), // Space for minumum argument count
ARGCOUNTMIN1 = GENX_ITR_FLAGENUM(0, 1), // Must have at least one argument
BITWIDTH = GENX_ITR_CATVAL(0x1a), // bit width of svm atomic instructions
// A field that contains an operand number, other than general, and it
// is the "real" use of the operand, rather than an auxiliary use
// such as a "number of GRFs" field relating to this operand.
FIRST_REAL_OPERAND = GENX_ITR_CATVAL(0x20),
BYTE = GENX_ITR_CATVAL(0x20), // constant byte operand
SHORT = GENX_ITR_CATVAL(0x21), // constant short operand
INT = GENX_ITR_CATVAL(0x22), // constant int operand
ADDRESS = GENX_ITR_CATVAL(0x23), // address operand
PREDICATE = GENX_ITR_CATVAL(0x24), // predicate operand
PREDICATE_ZEROED = GENX_ITR_FLAGVAL(0),
Z_PREDICATE = PREDICATE | PREDICATE_ZEROED,
SAMPLER = GENX_ITR_CATVAL(0x25), // sampler operand
SURFACE = GENX_ITR_CATVAL(0x26), // surface operand
// byte height of media 2D block, inferred from the width operand
// pointed at and the size of the return type or final operand type
MEDIAHEIGHT = GENX_ITR_CATVAL(0x27),
// predication control field from explicit predicate arg
PREDICATION = GENX_ITR_CATVAL(0x28),
// chmask field in load/sample, with exec size bit
SAMPLECHMASK = GENX_ITR_CATVAL(0x29),
// does not appear in the vISA output, but needs to be two address
// coalesced with result
TWOADDR = GENX_ITR_CATVAL(0x2a),
CONSTVI1ASI32 = GENX_ITR_CATVAL(0x2b), // constant vXi1 written as i32 (used in setp)
RAW = GENX_ITR_CATVAL(0x2c), // raw operand or result,
// Raw descriptor flags, 3 bits used
RAW_UNSIGNED = GENX_ITR_FLAGVAL(0), // raw operand/result must be unsigned
RAW_SIGNED = GENX_ITR_FLAGVAL(1), // raw operand/result must be signed
RAW_NULLALLOWED = GENX_ITR_FLAGVAL(2), // raw operand or result can be null (V0)
URAW = RAW | RAW_UNSIGNED,
SRAW = RAW | RAW_SIGNED,
EXECSIZE_NOMASK = GENX_ITR_CATVAL(0x2d), // execution size with NoMask
// A general operand
GENERAL = GENX_ITR_CATVAL(0x2e),
// A general operand with compile-time signedness choosing
GENERAL_CTSIGN = GENERAL,
// A predefined surface operand
PREDEF_SURFACE = GENX_ITR_CATVAL(0x2f),
// Modifiers for destination or source, 7 bits used
UNSIGNED = GENX_ITR_FLAGVAL(0), // int type forced to unsigned
SIGNED = GENX_ITR_FLAGVAL(1), // int type forced to signed
OWALIGNED = GENX_ITR_FLAGVAL(2), // must be oword aligned
GRFALIGNED = GENX_ITR_FLAGVAL(3), // must be grf aligned
RESTRICTION = GENX_ITR_FLAGMASK(4, 3), // field with operand width restriction
FIXED4 = GENX_ITR_FLAGENUM(4, 1), // operand is fixed size 4 vector and contiguous
CONTIGUOUS = GENX_ITR_FLAGENUM(4, 2), // operand must be contiguous
SCALARORCONTIGUOUS = GENX_ITR_FLAGENUM(4, 3), // operand must be stride 0 or contiguous
TWICEWIDTH = GENX_ITR_FLAGENUM(4, 4), // operand is twice the execution width
STRIDE1 = GENX_ITR_FLAGENUM(4, 5), // horizontal stride must be 1
ONLY_LEGAL_REGION = GENX_ITR_FLAGENUM(4, 6), // instruction can be baled with only legal
// region that won`t be splitted
// Modifiers for destination only, 2 bits used
SATURATION = GENX_ITR_FLAGMASK(7, 2),
SATURATION_DEFAULT = GENX_ITR_FLAGENUM(7, 0), // saturation default: not saturated, fp is
// allowed to bale in to saturate inst
SATURATION_SATURATE = GENX_ITR_FLAGENUM(7, 1), // saturated
SATURATION_NOSAT = GENX_ITR_FLAGENUM(7, 2), // fp not allowed to bale in to saturate inst
SATURATION_INTALLOWED = GENX_ITR_FLAGENUM(7, 3), // int is allowed to bale in to saturate,
// because inst cannot overflow so
// saturation only required on destination
// truncation
// Modifiers for source only, 3 bits used
NOIMM = GENX_ITR_FLAGVAL(7), // source not allowed to be immediate
MODIFIER = GENX_ITR_FLAGMASK(8, 2),
MODIFIER_DEFAULT = GENX_ITR_FLAGENUM(8, 0), // src modifier default: none
MODIFIER_ARITH = GENX_ITR_FLAGENUM(8, 1), // src modifier: arithmetic
MODIFIER_LOGIC = GENX_ITR_FLAGENUM(8, 2), // src modifier: logic
MODIFIER_EXTONLY = GENX_ITR_FLAGENUM(8, 3), // src modifier: extend only
DIRECTONLY = GENX_ITR_FLAGVAL(10), // indirect region not allowed
};
struct ArgInfo {
unsigned Info;
// Construct argument with empty info.
ArgInfo() : Info(0) {}
// Construct from a field read from the intrinsics info table.
ArgInfo(unsigned Info) : Info(Info) {}
// getCategory : return field category
unsigned getCategory() const { return Info & CATMASK; }
// getAlignment : get any special alignment requirement, else align to 1
// byte
VISA_Align getAlignment() const {
if (isGeneral()) {
if (Info & GRFALIGNED)
return VISA_Align::ALIGN_GRF;
if (Info & OWALIGNED)
return VISA_Align::ALIGN_OWORD;
return VISA_Align::ALIGN_BYTE;
}
if (isRaw())
return VISA_Align::ALIGN_GRF;
return VISA_Align::ALIGN_BYTE;
}
// isGeneral : test whether this is a general operand
bool isGeneral() const { return getCategory() == GENERAL; }
bool needsSigned() const {
if (isGeneral())
return Info & SIGNED;
if (isRaw())
return Info & RAW_SIGNED;
return false;
}
bool needsUnsigned() const {
if (isGeneral())
return Info & UNSIGNED;
if (isRaw())
return Info & RAW_UNSIGNED;
return false;
}
bool isDirectOnly() const { return Info & DIRECTONLY; }
bool rawNullAllowed() const {
IGC_ASSERT(isRaw());
return Info & RAW_NULLALLOWED;
}
// isArgOrRet : test whether this field has an arg index
bool isArgOrRet() const {
if (isGeneral()) return true;
if ((Info & CATMASK) >= FIRST_OPERAND)
return true;
return false;
}
// isRealArgOrRet : test whether this field has an arg index, and is
// a "real" use of the arg
bool isRealArgOrRet() const {
if (isGeneral()) return true;
if ((Info & CATMASK) >= FIRST_REAL_OPERAND)
return true;
return false;
}
// getArgCountMin : return minimum number of arguments
int getArgCountMin() const {
IGC_ASSERT(getCategory() == ARGCOUNT);
return (Info & ARGCOUNTMASK) >> FLAGBASE;
}
// getArgIdx : return argument index for this field, or -1 for return value
// (assuming isArgOrRet())
int getArgIdx() const {
IGC_ASSERT(isArgOrRet());
return (Info & OPNDMASK) - 1;
}
// getLiteral : for a LITERAL or EXECSIZE field, return the literal value
unsigned getLiteral() const { return Info & LITMASK; }
// isRet : test whether this is the field for the return value
// (assuming isArgOrRet())
bool isRet() const { return getArgIdx() < 0; }
// isRaw : test whether this is a raw arg or return value
bool isRaw() const { return getCategory() == RAW; }
// getSaturation : return saturation info for the arg
unsigned getSaturation() const { return Info & SATURATION; }
// getRestriction : return operand width/region restriction, one of
// 0 (no restriction), FIXED4, CONTIGUOUS, TWICEWIDTH
unsigned getRestriction() const { return Info & RESTRICTION; }
// isImmediateDisallowed : test whether immediate disallowed
// (assuming isArgOrRet())
bool isImmediateDisallowed() const {
IGC_ASSERT(isArgOrRet());
if (isGeneral())
return Info & NOIMM;
if (isRaw())
return true;
switch (Info & CATMASK) {
case TWOADDR:
case PREDICATION:
case SURFACE:
case SAMPLER:
return true;
default: break;
}
return false;
}
// getModifier : get what source modifier is allowed
unsigned getModifier() const {
IGC_ASSERT(isGeneral());
IGC_ASSERT(isArgOrRet());
IGC_ASSERT(!isRet());
return Info & MODIFIER;
}
};
using DescrType = llvm::SmallVector<ArgInfo, 8>;
// Construct a GenXIntrinsicInfo for a particular intrinsic
GenXIntrinsicInfo(unsigned IntrinId) { InfoIt = getTable().find(IntrinId); }
bool isNull() const { return InfoIt == getTable().cend(); }
bool isNotNull() const { return !isNull(); }
// Return instruction description.
ArrayRef<ArgInfo> getInstDesc() const {
return isNull() ? ArrayRef<ArgInfo>{} : ArrayRef<ArgInfo>{InfoIt->second};
}
// Get the category and modifier for an arg idx
ArgInfo getArgInfo(int Idx) const;
// Get the trailing null zone, if any.
unsigned getTrailingNullZoneStart(CallInst *CI) const;
// Get the category and modifier for the return value
ArgInfo getRetInfo() const { return getArgInfo(-1); }
// Get bitmap of allowed execution sizes
unsigned getExecSizeAllowedBits() const;
// Determine if a predicated destination mask is permitted
bool getPredAllowed() const;
// Determine if intrinsic is element-wise
bool isElementWise() const;
// Get The overrided execution size or 0.
static unsigned getOverridedExecSize(CallInst *CI,
const GenXSubtarget *ST = nullptr);
private:
using TableType = std::unordered_map<unsigned, DescrType>;
static const TableType &getTable();
TableType::const_iterator InfoIt;
};
} // namespace llvm
#endif // ndef GENXINTRINSICS_H
|