llvm/clang/include/clang/Basic/arm_sve_sme_incl.td

//===--- arm_sve_sme_incl.td - ARM SVE/SME compiler interface -------------===//
//
//  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
//
//===----------------------------------------------------------------------===//
//
//  This file defines common properites of TableGen definitions use for both
//  SVE and SME intrinsics.
//
//      https://developer.arm.com/architectures/system-architectures/software-standards/acle
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Instruction definitions
//===----------------------------------------------------------------------===//
// Every intrinsic subclasses "Inst". An intrinsic has a name, a prototype and
// a sequence of typespecs.
//
// The name is the base name of the intrinsic, for example "svld1". This is
// then mangled by the tblgen backend to add type information ("svld1_s16").
//
// A typespec is a sequence of uppercase characters (modifiers) followed by one
// lowercase character. A typespec encodes a particular "base type" of the
// intrinsic.
//
// An example typespec is "Us" - unsigned short - svuint16_t. The available
// typespec codes are given below.
//
// The string given to an Inst class is a sequence of typespecs. The intrinsic
// is instantiated for every typespec in the sequence. For example "sdUsUd".
//
// The prototype is a string that defines the return type of the intrinsic
// and the type of each argument. The return type and every argument gets a
// "modifier" that can change in some way the "base type" of the intrinsic.
//
// The modifier 'd' means "default" and does not modify the base type in any
// way. The available modifiers are given below.
//
// Typespecs
// ---------
// c: char
// s: short
// i: int
// l: long
// q: int128_t
// f: float
// h: half-float
// d: double
// b: bfloat

// Typespec modifiers
// ------------------
// P: boolean
// U: unsigned
// Q: svcount

// Prototype modifiers
// -------------------
// prototype: return (arg, arg, ...)
//
// 2,3,4: array of vectors
// .: indicator for multi-vector modifier that will follow (e.g. 2.x)
// v: void
// x: vector of signed integers
// u: vector of unsigned integers
// d: default
// c: const pointer type
// P: predicate type
// s: scalar of element type
// a: scalar of element type (splat to vector type)
// R: scalar of 1/2 width element type (splat to vector type)
// r: scalar of 1/4 width element type (splat to vector type)
// @: unsigned scalar of 1/4 width element type (splat to vector type)
// e: 1/2 width unsigned elements, 2x element count
// b: 1/4 width unsigned elements, 4x element count
// h: 1/2 width elements, 2x element count
// q: 1/4 width elements, 4x element count
// o: 4x width elements, 1/4 element count
//
// w: vector of element type promoted to 64bits, vector maintains
//    signedness of its element type.
// f: element type promoted to uint64_t (splat to vector type)
// j: element type promoted to 64bits (splat to vector type)
// K: element type bitcast to a signed integer (splat to vector type)
// L: element type bitcast to an unsigned integer (splat to vector type)
//
// i: constant uint64_t
// k: int32_t
// l: int64_t
// m: uint32_t
// n: uint64_t

// [: svuint8_t
// t: svint32_t
// z: svuint32_t
// g: svuint64_t
// O: svfloat16_t
// M: svfloat32_t
// N: svfloat64_t
// $: svbfloat16_t

// J: Prefetch type (sv_prfop)

// %: pointer to void

// A: pointer to int8_t
// B: pointer to int16_t
// C: pointer to int32_t
// D: pointer to int64_t

// E: pointer to uint8_t
// F: pointer to uint16_t
// G: pointer to uint32_t
// H: pointer to uint64_t

// Q: const pointer to void

// S: const pointer to int8_t
// T: const pointer to int16_t
// U: const pointer to int32_t
// V: const pointer to int64_t
//
// W: const pointer to uint8_t
// X: const pointer to uint16_t
// Y: const pointer to uint32_t
// Z: const pointer to uint64_t

// Prototype modifiers added for SVE2p1
// {: 128b vector
// }: svcount_t

class MergeType<int val, string suffix=""> {
  int Value = val;
  string Suffix = suffix;
}
def MergeNone    : MergeType<0>;
def MergeAny     : MergeType<1, "_x">;
def MergeOp1     : MergeType<2, "_m">;
def MergeZero    : MergeType<3, "_z">;
def MergeAnyExp  : MergeType<4, "_x">; // Use merged builtin with explicit
def MergeZeroExp : MergeType<5, "_z">; // generation of its inactive argument.

class EltType<int val> {
  int Value = val;
}
def EltTyInvalid : EltType<0>;
def EltTyInt8    : EltType<1>;
def EltTyInt16   : EltType<2>;
def EltTyInt32   : EltType<3>;
def EltTyInt64   : EltType<4>;
def EltTyInt128  : EltType<5>;
def EltTyFloat16 : EltType<6>;
def EltTyFloat32 : EltType<7>;
def EltTyFloat64 : EltType<8>;
def EltTyBool8   : EltType<9>;
def EltTyBool16  : EltType<10>;
def EltTyBool32  : EltType<11>;
def EltTyBool64  : EltType<12>;
def EltTyBFloat16 : EltType<13>;

class MemEltType<int val> {
  int Value = val;
}
def MemEltTyDefault   : MemEltType<0>;
def MemEltTyInt8      : MemEltType<1>;
def MemEltTyInt16     : MemEltType<2>;
def MemEltTyInt32     : MemEltType<3>;
def MemEltTyInt64     : MemEltType<4>;

class FlagType<int val> {
  int Value = val;
}

// These must be kept in sync with the flags in utils/TableGen/SveEmitter.h
// and include/clang/Basic/TargetBuiltins.h
def NoFlags                   : FlagType<0x00000000>;
def FirstEltType              : FlagType<0x00000001>;
//      :                                     :
//      :                                     :
def EltTypeMask               : FlagType<0x0000000f>;
def FirstMemEltType           : FlagType<0x00000010>;
//      :                                     :
//      :                                     :
def MemEltTypeMask            : FlagType<0x00000070>;
def FirstMergeTypeMask        : FlagType<0x00000080>;
//      :                                     :
//      :                                     :
def MergeTypeMask             : FlagType<0x00000380>;
def FirstSplatOperand         : FlagType<0x00000400>;
//      :                                     :
// These flags are used to specify which scalar operand
// needs to be duplicated/splatted into a vector.
//      :                                     :
def SplatOperandMask                : FlagType<0x00001C00>;
def IsLoad                          : FlagType<0x00002000>;
def IsStore                         : FlagType<0x00004000>;
def IsGatherLoad                    : FlagType<0x00008000>;
def IsScatterStore                  : FlagType<0x00010000>;
def IsStructLoad                    : FlagType<0x00020000>;
def IsStructStore                   : FlagType<0x00040000>;
def IsZExtReturn                    : FlagType<0x00080000>; // Return value is sign-extend by default
def IsOverloadNone                  : FlagType<0x00100000>; // Intrinsic does not take any overloaded types.
def IsOverloadWhileOrMultiVecCvt    : FlagType<0x00200000>; // Use {default type, typeof(operand1)} as overloaded types.
def IsOverloadWhileRW               : FlagType<0x00400000>; // Use {pred(default type), typeof(operand0)} as overloaded types.
def IsOverloadCvt                   : FlagType<0x00800000>; // Use {typeof(operand0), typeof(last operand)} as overloaded types.
def OverloadKindMask                : FlagType<0x00E00000>; // When the masked values are all '0', the default type is used as overload type.
def IsByteIndexed                   : FlagType<0x01000000>;
def IsAppendSVALL                   : FlagType<0x02000000>; // Appends SV_ALL as the last operand.
def IsInsertOp1SVALL                : FlagType<0x04000000>; // Inserts SV_ALL as the second operand.
def IsPrefetch                      : FlagType<0x08000000>; // Contiguous prefetches.
def IsGatherPrefetch                : FlagType<0x10000000>;
def ReverseCompare                  : FlagType<0x20000000>; // Compare operands must be swapped.
def ReverseUSDOT                    : FlagType<0x40000000>; // Unsigned/signed operands must be swapped.
def IsUndef                         : FlagType<0x80000000>; // Codegen `undef` of given type.
def IsTupleCreate                   : FlagType<0x100000000>;
def IsTupleGet                      : FlagType<0x200000000>;
def IsTupleSet                      : FlagType<0x400000000>;
def ReverseMergeAnyBinOp            : FlagType<0x800000000>; // e.g. Implement SUBR_X using SUB_X.
def ReverseMergeAnyAccOp            : FlagType<0x1000000000>; // e.g. Implement MSB_X using MLS_X.
def IsStreaming                     : FlagType<0x2000000000>;
def IsStreamingCompatible           : FlagType<0x4000000000>;
def IsReadZA                        : FlagType<0x8000000000>;
def IsWriteZA                       : FlagType<0x10000000000>;
def IsReductionQV                   : FlagType<0x20000000000>;
def VerifyRuntimeMode               : FlagType<0x40000000000>; // Use for intrinsics that are common between SVE and SME.
def IsInZA                          : FlagType<0x80000000000>;
def IsOutZA                         : FlagType<0x100000000000>;
def IsInOutZA                       : FlagType<0x200000000000>;
def IsInZT0                         : FlagType<0x400000000000>;
def IsOutZT0                        : FlagType<0x800000000000>;
def IsInOutZT0                      : FlagType<0x1000000000000>;

// These must be kept in sync with the flags in include/clang/Basic/TargetBuiltins.h
class ImmCheckType<int val> {
  int Value = val;
}
def ImmCheck0_31                : ImmCheckType<0>;  // 0..31 (used for e.g. predicate patterns)
def ImmCheck1_16                : ImmCheckType<1>;  // 1..16
def ImmCheckExtract             : ImmCheckType<2>;  // 0..(2048/sizeinbits(elt) - 1)
def ImmCheckShiftRight          : ImmCheckType<3>;  // 1..sizeinbits(elt)
def ImmCheckShiftRightNarrow    : ImmCheckType<4>;  // 1..sizeinbits(elt)/2
def ImmCheckShiftLeft           : ImmCheckType<5>;  // 0..(sizeinbits(elt) - 1)
def ImmCheck0_7                 : ImmCheckType<6>;  // 0..7
def ImmCheckLaneIndex           : ImmCheckType<7>;  // 0..(128/(1*sizeinbits(elt)) - 1)
def ImmCheckLaneIndexCompRotate : ImmCheckType<8>;  // 0..(128/(2*sizeinbits(elt)) - 1)
def ImmCheckLaneIndexDot        : ImmCheckType<9>;  // 0..(128/(4*sizeinbits(elt)) - 1)
def ImmCheckComplexRot90_270    : ImmCheckType<10>; // [90,270]
def ImmCheckComplexRotAll90     : ImmCheckType<11>; // [0, 90, 180,270]
def ImmCheck0_13                : ImmCheckType<12>; // 0..13
def ImmCheck0_1                 : ImmCheckType<13>; // 0..1
def ImmCheck0_2                 : ImmCheckType<14>; // 0..2
def ImmCheck0_3                 : ImmCheckType<15>; // 0..3
def ImmCheck0_0                 : ImmCheckType<16>; // 0..0
def ImmCheck0_15                : ImmCheckType<17>; // 0..15
def ImmCheck0_255               : ImmCheckType<18>; // 0..255
def ImmCheck2_4_Mul2            : ImmCheckType<19>; // 2, 4
def ImmCheck1_1                 : ImmCheckType<20>; // 1..1
def ImmCheck1_3                 : ImmCheckType<21>; // 1..3
def ImmCheck1_7                 : ImmCheckType<22>; // 1..7

class ImmCheck<int arg, ImmCheckType kind, int eltSizeArg = -1> {
  int Arg = arg;
  int EltSizeArg = eltSizeArg;
  ImmCheckType Kind = kind;
}

defvar InvalidMode = "";

class Inst<string n, string p, string t, MergeType mt, string i,
           list<FlagType> ft, list<ImmCheck> ch, MemEltType met = MemEltTyDefault> {
  string Name = n;
  string Prototype = p;
  string Types = t;
  string SVETargetGuard = "sve";
  string SMETargetGuard = "sme";
  int Merge = mt.Value;
  string MergeSuffix = mt.Suffix;
  string LLVMIntrinsic = i;
  list<FlagType> Flags = ft;
  list<ImmCheck> ImmChecks = ch;
  int MemEltType = met.Value;
}

// SInst: Instruction with signed/unsigned suffix (e.g., "s8", "u8")
class SInst<string n, string p, string t, MergeType mt, string i = "",
            list<FlagType> ft = [], list<ImmCheck> ch = []>
    : Inst<n, p, t, mt, i, ft, ch, MemEltTyDefault> {
}

// MInst: Instructions which access memory
class MInst<string n, string p, string t, list<FlagType> f,
            MemEltType met = MemEltTyDefault, string i = "",
            list<ImmCheck> ch = []>
    : Inst<n, p, t, MergeNone, i, f, ch, met> {
}