diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -334,13 +334,18 @@ Value: `SimpleValue` `ValueSuffix`* :| `Value` "#" [`Value`] ValueSuffix: "{" `RangeList` "}" - :| "[" `RangeList` "]" + :| "[" `SliceElements` "]" :| "." `TokIdentifier` RangeList: `RangePiece` ("," `RangePiece`)* RangePiece: `TokInteger` :| `TokInteger` "..." `TokInteger` :| `TokInteger` "-" `TokInteger` :| `TokInteger` `TokInteger` + SliceElements: (`SliceElement` ",")* `SliceElement` ","? + SliceElement: `Value` + :| `Value` "..." `Value` + :| `Value` "-" `Value` + :| `Value` `TokInteger`(negative) .. warning:: The peculiar last form of :token:`RangePiece` is due to the fact that the @@ -504,17 +509,26 @@ The final value is bits 8--15 of the integer *value*. The order of the bits can be reversed by specifying ``{15...8}``. -*value*\ ``[4]`` - The final value is element 4 of the list *value* (note the brackets). +*value*\ ``[i]`` + The final value is element `i` of the list *value* (note the brackets). In other words, the brackets act as a subscripting operator on the list. This is the case only when a single element is specified. +*value*\ ``[i,]`` + The final value is a list that contains a single element `i` of the list. + In short, a list slice with a single element. + *value*\ ``[4...7,17,2...3,4]`` The final value is a new list that is a slice of the list *value*. The new list contains elements 4, 5, 6, 7, 17, 2, 3, and 4. Elements may be included multiple times and in any order. This is the result only when more than one element is specified. + *value*\ ``[i,m...n,j,ls]`` + Each element may be an expression (variables, bang operators). + The type of `m` and `n` should be `int`. + The tyep of `i`, `j`, and `ls` should be either `int` or `list`. + *value*\ ``.``\ *field* The final value is the value of the specified *field* in the specified record *value*. @@ -1782,6 +1796,15 @@ result. A logical OR can be performed if all the arguments are either 0 or 1. +``!range([``\ *a*\ ``,``] *b*\ ``)`` + This operator produces half-open range sequence ``[a : b)`` as ``list``. + *a* is ``0`` by default. ``!range(4)`` is equivalent to ``!range(0, 4)``. + Its result is `[0, 1, 2, 3]`. + The result is `[]>` if *a* ``>=`` *b*. + +``!range([``\ *list*\ ``)`` + Equivalent to ``!range(0, !size(list))``. + ``!setdagop(``\ *dag*\ ``,`` *op*\ ``)`` This operator produces a DAG node with the same arguments as *dag*, but with its operator replaced with *op*. diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td --- a/llvm/include/llvm/CodeGen/ValueTypes.td +++ b/llvm/include/llvm/CodeGen/ValueTypes.td @@ -16,217 +16,255 @@ string Namespace = "MVT"; int Size = size; int Value = value; + int nElem = 1; + ValueType ElementType = ?; + int isOverloaded = false; + int isInteger = false; + int isFP = false; + int isVector = false; + int isScalable = false; } +class VTAny : ValueType<0, value> { + let isOverloaded = true; +} + +class VTInt + : ValueType { + let isInteger = true; +} + +class VTFP + : ValueType { + let isFP = true; +} + +class VTVec + : ValueType { + let nElem = nelem; + let ElementType = elt; + let isInteger = elt.isInteger; + let isFP = elt.isFP; + let isVector = true; +} + +class VTScalableVec + : VTVec { + let isScalable = true; +} + +defset list ValueTypes = { + def OtherVT : ValueType<0, 1>; // "Other" value -def i1 : ValueType<1, 2>; // One bit boolean value -def i2 : ValueType<2, 3>; // 2-bit integer value -def i4 : ValueType<4, 4>; // 4-bit integer value -def i8 : ValueType<8, 5>; // 8-bit integer value -def i16 : ValueType<16, 6>; // 16-bit integer value -def i32 : ValueType<32, 7>; // 32-bit integer value -def i64 : ValueType<64, 8>; // 64-bit integer value -def i128 : ValueType<128, 9>; // 128-bit integer value - -def bf16 : ValueType<16, 10>; // 16-bit brain floating point value -def f16 : ValueType<16, 11>; // 16-bit floating point value -def f32 : ValueType<32, 12>; // 32-bit floating point value -def f64 : ValueType<64, 13>; // 64-bit floating point value -def f80 : ValueType<80, 14>; // 80-bit floating point value -def f128 : ValueType<128, 15>; // 128-bit floating point value -def ppcf128 : ValueType<128, 16>; // PPC 128-bit floating point value - -def v1i1 : ValueType<1, 17>; // 1 x i1 vector value -def v2i1 : ValueType<2, 18>; // 2 x i1 vector value -def v4i1 : ValueType<4, 19>; // 4 x i1 vector value -def v8i1 : ValueType<8, 20>; // 8 x i1 vector value -def v16i1 : ValueType<16, 21>; // 16 x i1 vector value -def v32i1 : ValueType<32, 22>; // 32 x i1 vector value -def v64i1 : ValueType<64, 23>; // 64 x i1 vector value -def v128i1 : ValueType<128, 24>; // 128 x i1 vector value -def v256i1 : ValueType<256, 25>; // 256 x i1 vector value -def v512i1 : ValueType<512, 26>; // 512 x i1 vector value -def v1024i1 : ValueType<1024, 27>; // 1024 x i1 vector value -def v2048i1 : ValueType<2048, 28>; // 2048 x i1 vector value - -def v128i2 : ValueType<256, 29>; // 128 x i2 vector value -def v256i2 : ValueType<512, 30>; // 256 x i2 vector value - -def v64i4 : ValueType<256, 31>; // 64 x i4 vector value -def v128i4 : ValueType<512, 32>; // 128 x i4 vector value - -def v1i8 : ValueType<8, 33>; // 1 x i8 vector value -def v2i8 : ValueType<16, 34>; // 2 x i8 vector value -def v4i8 : ValueType<32, 35>; // 4 x i8 vector value -def v8i8 : ValueType<64, 36>; // 8 x i8 vector value -def v16i8 : ValueType<128, 37>; // 16 x i8 vector value -def v32i8 : ValueType<256, 38>; // 32 x i8 vector value -def v64i8 : ValueType<512, 39>; // 64 x i8 vector value -def v128i8 : ValueType<1024, 40>; // 128 x i8 vector value -def v256i8 : ValueType<2048, 41>; // 256 x i8 vector value -def v512i8 : ValueType<4096, 42>; // 512 x i8 vector value -def v1024i8 : ValueType<8192, 43>; // 1024 x i8 vector value - -def v1i16 : ValueType<16, 44>; // 1 x i16 vector value -def v2i16 : ValueType<32, 45>; // 2 x i16 vector value -def v3i16 : ValueType<48, 46>; // 3 x i16 vector value -def v4i16 : ValueType<64, 47>; // 4 x i16 vector value -def v8i16 : ValueType<128, 48>; // 8 x i16 vector value -def v16i16 : ValueType<256, 49>; // 16 x i16 vector value -def v32i16 : ValueType<512, 50>; // 32 x i16 vector value -def v64i16 : ValueType<1024, 51>; // 64 x i16 vector value -def v128i16 : ValueType<2048, 52>; // 128 x i16 vector value -def v256i16 : ValueType<4096, 53>; // 256 x i16 vector value -def v512i16 : ValueType<8192, 54>; // 512 x i16 vector value - -def v1i32 : ValueType<32, 55>; // 1 x i32 vector value -def v2i32 : ValueType<64, 56>; // 2 x i32 vector value -def v3i32 : ValueType<96, 57>; // 3 x i32 vector value -def v4i32 : ValueType<128, 58>; // 4 x i32 vector value -def v5i32 : ValueType<160, 59>; // 5 x i32 vector value -def v6i32 : ValueType<192, 60>; // 6 x f32 vector value -def v7i32 : ValueType<224, 61>; // 7 x f32 vector value -def v8i32 : ValueType<256, 62>; // 8 x i32 vector value -def v9i32 : ValueType<288, 63>; // 9 x i32 vector value -def v10i32 : ValueType<320, 64>; // 10 x i32 vector value -def v11i32 : ValueType<352, 65>; // 11 x i32 vector value -def v12i32 : ValueType<384, 66>; // 12 x i32 vector value -def v16i32 : ValueType<512, 67>; // 16 x i32 vector value -def v32i32 : ValueType<1024, 68>; // 32 x i32 vector value -def v64i32 : ValueType<2048, 69>; // 64 x i32 vector value -def v128i32 : ValueType<4096, 70>; // 128 x i32 vector value -def v256i32 : ValueType<8192, 71>; // 256 x i32 vector value -def v512i32 : ValueType<16384, 72>; // 512 x i32 vector value -def v1024i32 : ValueType<32768, 73>; // 1024 x i32 vector value -def v2048i32 : ValueType<65536, 74>; // 2048 x i32 vector value - -def v1i64 : ValueType<64, 75>; // 1 x i64 vector value -def v2i64 : ValueType<128, 76>; // 2 x i64 vector value -def v3i64 : ValueType<192, 77>; // 3 x i64 vector value -def v4i64 : ValueType<256, 78>; // 4 x i64 vector value -def v8i64 : ValueType<512, 79>; // 8 x i64 vector value -def v16i64 : ValueType<1024, 80>; // 16 x i64 vector value -def v32i64 : ValueType<2048, 81>; // 32 x i64 vector value -def v64i64 : ValueType<4096, 82>; // 64 x i64 vector value -def v128i64 : ValueType<8192, 83>; // 128 x i64 vector value -def v256i64 : ValueType<16384, 84>; // 256 x i64 vector value - -def v1i128 : ValueType<128, 85>; // 1 x i128 vector value - -def v1f16 : ValueType<16, 86>; // 1 x f16 vector value -def v2f16 : ValueType<32, 87>; // 2 x f16 vector value -def v3f16 : ValueType<48, 88>; // 3 x f16 vector value -def v4f16 : ValueType<64, 89>; // 4 x f16 vector value -def v8f16 : ValueType<128, 90>; // 8 x f16 vector value -def v16f16 : ValueType<256, 91>; // 16 x f16 vector value -def v32f16 : ValueType<512, 92>; // 32 x f16 vector value -def v64f16 : ValueType<1024, 93>; // 64 x f16 vector value -def v128f16 : ValueType<2048, 94>; // 128 x f16 vector value -def v256f16 : ValueType<4096, 95>; // 256 x f16 vector value -def v512f16 : ValueType<8192, 96>; // 512 x f16 vector value - -def v2bf16 : ValueType<32, 97>; // 2 x bf16 vector value -def v3bf16 : ValueType<48, 98>; // 3 x bf16 vector value -def v4bf16 : ValueType<64, 99>; // 4 x bf16 vector value -def v8bf16 : ValueType<128, 100>; // 8 x bf16 vector value -def v16bf16 : ValueType<256, 101>; // 16 x bf16 vector value -def v32bf16 : ValueType<512, 102>; // 32 x bf16 vector value -def v64bf16 : ValueType<1024, 103>; // 64 x bf16 vector value -def v128bf16 : ValueType<2048, 104>; // 128 x bf16 vector value - -def v1f32 : ValueType<32, 105>; // 1 x f32 vector value -def v2f32 : ValueType<64, 106>; // 2 x f32 vector value -def v3f32 : ValueType<96, 107>; // 3 x f32 vector value -def v4f32 : ValueType<128, 108>; // 4 x f32 vector value -def v5f32 : ValueType<160, 109>; // 5 x f32 vector value -def v6f32 : ValueType<192, 110>; // 6 x f32 vector value -def v7f32 : ValueType<224, 111>; // 7 x f32 vector value -def v8f32 : ValueType<256, 112>; // 8 x f32 vector value -def v9f32 : ValueType<288, 113>; // 9 x f32 vector value -def v10f32 : ValueType<320, 114>; // 10 x f32 vector value -def v11f32 : ValueType<352, 115>; // 11 x f32 vector value -def v12f32 : ValueType<384, 116>; // 12 x f32 vector value -def v16f32 : ValueType<512, 117>; // 16 x f32 vector value -def v32f32 : ValueType<1024, 118>; // 32 x f32 vector value -def v64f32 : ValueType<2048, 119>; // 64 x f32 vector value -def v128f32 : ValueType<4096, 120>; // 128 x f32 vector value -def v256f32 : ValueType<8192, 121>; // 256 x f32 vector value -def v512f32 : ValueType<16384, 122>; // 512 x f32 vector value -def v1024f32 : ValueType<32768, 123>; // 1024 x f32 vector value -def v2048f32 : ValueType<65536, 124>; // 2048 x f32 vector value - -def v1f64 : ValueType<64, 125>; // 1 x f64 vector value -def v2f64 : ValueType<128, 126>; // 2 x f64 vector value -def v3f64 : ValueType<192, 127>; // 3 x f64 vector value -def v4f64 : ValueType<256, 128>; // 4 x f64 vector value -def v8f64 : ValueType<512, 129>; // 8 x f64 vector value -def v16f64 : ValueType<1024, 130>; // 16 x f64 vector value -def v32f64 : ValueType<2048, 131>; // 32 x f64 vector value -def v64f64 : ValueType<4096, 132>; // 64 x f64 vector value -def v128f64 : ValueType<8192, 133>; // 128 x f64 vector value -def v256f64 : ValueType<16384, 134>; // 256 x f64 vector value - -def nxv1i1 : ValueType<1, 135>; // n x 1 x i1 vector value -def nxv2i1 : ValueType<2, 136>; // n x 2 x i1 vector value -def nxv4i1 : ValueType<4, 137>; // n x 4 x i1 vector value -def nxv8i1 : ValueType<8, 138>; // n x 8 x i1 vector value -def nxv16i1 : ValueType<16, 139>; // n x 16 x i1 vector value -def nxv32i1 : ValueType<32, 140>; // n x 32 x i1 vector value -def nxv64i1 : ValueType<64, 141>; // n x 64 x i1 vector value - -def nxv1i8 : ValueType<8, 142>; // n x 1 x i8 vector value -def nxv2i8 : ValueType<16, 143>; // n x 2 x i8 vector value -def nxv4i8 : ValueType<32, 144>; // n x 4 x i8 vector value -def nxv8i8 : ValueType<64, 145>; // n x 8 x i8 vector value -def nxv16i8 : ValueType<128, 146>; // n x 16 x i8 vector value -def nxv32i8 : ValueType<256, 147>; // n x 32 x i8 vector value -def nxv64i8 : ValueType<512, 148>; // n x 64 x i8 vector value - -def nxv1i16 : ValueType<16, 149>; // n x 1 x i16 vector value -def nxv2i16 : ValueType<32, 150>; // n x 2 x i16 vector value -def nxv4i16 : ValueType<64, 151>; // n x 4 x i16 vector value -def nxv8i16 : ValueType<128, 152>; // n x 8 x i16 vector value -def nxv16i16 : ValueType<256, 153>; // n x 16 x i16 vector value -def nxv32i16 : ValueType<512, 154>; // n x 32 x i16 vector value - -def nxv1i32 : ValueType<32, 155>; // n x 1 x i32 vector value -def nxv2i32 : ValueType<64, 156>; // n x 2 x i32 vector value -def nxv4i32 : ValueType<128, 157>; // n x 4 x i32 vector value -def nxv8i32 : ValueType<256, 158>; // n x 8 x i32 vector value -def nxv16i32 : ValueType<512, 159>; // n x 16 x i32 vector value -def nxv32i32 : ValueType<1024, 160>; // n x 32 x i32 vector value - -def nxv1i64 : ValueType<64, 161>; // n x 1 x i64 vector value -def nxv2i64 : ValueType<128, 162>; // n x 2 x i64 vector value -def nxv4i64 : ValueType<256, 163>; // n x 4 x i64 vector value -def nxv8i64 : ValueType<512, 164>; // n x 8 x i64 vector value -def nxv16i64 : ValueType<1024, 165>; // n x 16 x i64 vector value -def nxv32i64 : ValueType<2048, 166>; // n x 32 x i64 vector value - -def nxv1f16 : ValueType<16, 167>; // n x 1 x f16 vector value -def nxv2f16 : ValueType<32, 168>; // n x 2 x f16 vector value -def nxv4f16 : ValueType<64, 169>; // n x 4 x f16 vector value -def nxv8f16 : ValueType<128, 170>; // n x 8 x f16 vector value -def nxv16f16 : ValueType<256, 171>; // n x 16 x f16 vector value -def nxv32f16 : ValueType<512, 172>; // n x 32 x f16 vector value - -def nxv1bf16 : ValueType<16, 173>; // n x 1 x bf16 vector value -def nxv2bf16 : ValueType<32, 174>; // n x 2 x bf16 vector value -def nxv4bf16 : ValueType<64, 175>; // n x 4 x bf16 vector value -def nxv8bf16 : ValueType<128, 176>; // n x 8 x bf16 vector value -def nxv16bf16 : ValueType<256, 177>; // n x 16 x bf16 vector value -def nxv32bf16 : ValueType<512, 178>; // n x 32 x bf16 vector value - -def nxv1f32 : ValueType<32, 179>; // n x 1 x f32 vector value -def nxv2f32 : ValueType<64, 180>; // n x 2 x f32 vector value -def nxv4f32 : ValueType<128, 181>; // n x 4 x f32 vector value -def nxv8f32 : ValueType<256, 182>; // n x 8 x f32 vector value -def nxv16f32 : ValueType<512, 183>; // n x 16 x f32 vector value - -def nxv1f64 : ValueType<64, 184>; // n x 1 x f64 vector value -def nxv2f64 : ValueType<128, 185>; // n x 2 x f64 vector value -def nxv4f64 : ValueType<256, 186>; // n x 4 x f64 vector value -def nxv8f64 : ValueType<512, 187>; // n x 8 x f64 vector value + +def i1 : VTInt<1, 2>; // One bit boolean value +def i2 : VTInt<2, 3>; // 2-bit integer value +def i4 : VTInt<4, 4>; // 4-bit integer value +def i8 : VTInt<8, 5>; // 8-bit integer value +def i16 : VTInt<16, 6>; // 16-bit integer value +def i32 : VTInt<32, 7>; // 32-bit integer value +def i64 : VTInt<64, 8>; // 64-bit integer value +def i128 : VTInt<128, 9>; // 128-bit integer value + +def bf16 : VTFP<16, 10>; // 16-bit brain floating point value +def f16 : VTFP<16, 11>; // 16-bit floating point value +def f32 : VTFP<32, 12>; // 32-bit floating point value +def f64 : VTFP<64, 13>; // 64-bit floating point value +def f80 : VTFP<80, 14>; // 80-bit floating point value +def f128 : VTFP<128, 15>; // 128-bit floating point value +def ppcf128 : VTFP<128, 16>; // PPC 128-bit floating point value + +def v1i1 : VTVec<1, i1, 17>; // 1 x i1 vector value +def v2i1 : VTVec<2, i1, 18>; // 2 x i1 vector value +def v4i1 : VTVec<4, i1, 19>; // 4 x i1 vector value +def v8i1 : VTVec<8, i1, 20>; // 8 x i1 vector value +def v16i1 : VTVec<16, i1, 21>; // 16 x i1 vector value +def v32i1 : VTVec<32, i1, 22>; // 32 x i1 vector value +def v64i1 : VTVec<64, i1, 23>; // 64 x i1 vector value +def v128i1 : VTVec<128, i1, 24>; // 128 x i1 vector value +def v256i1 : VTVec<256, i1, 25>; // 256 x i1 vector value +def v512i1 : VTVec<512, i1, 26>; // 512 x i1 vector value +def v1024i1 : VTVec<1024, i1, 27>; // 1024 x i1 vector value +def v2048i1 : VTVec<2048, i1, 28>; // 2048 x i1 vector value + +def v128i2 : VTVec<128, i2, 29>; // 128 x i2 vector value +def v256i2 : VTVec<256, i2, 30>; // 256 x i2 vector value + +def v64i4 : VTVec<64, i4, 31>; // 64 x i4 vector value +def v128i4 : VTVec<128, i4, 32>; // 128 x i4 vector value + +def v1i8 : VTVec<1, i8, 33>; // 1 x i8 vector value +def v2i8 : VTVec<2, i8, 34>; // 2 x i8 vector value +def v4i8 : VTVec<4, i8, 35>; // 4 x i8 vector value +def v8i8 : VTVec<8, i8, 36>; // 8 x i8 vector value +def v16i8 : VTVec<16, i8, 37>; // 16 x i8 vector value +def v32i8 : VTVec<32, i8, 38>; // 32 x i8 vector value +def v64i8 : VTVec<64, i8, 39>; // 64 x i8 vector value +def v128i8 : VTVec<128, i8, 40>; // 128 x i8 vector value +def v256i8 : VTVec<256, i8, 41>; // 256 x i8 vector value +def v512i8 : VTVec<512, i8, 42>; // 512 x i8 vector value +def v1024i8 : VTVec<1024, i8, 43>; // 1024 x i8 vector value + +def v1i16 : VTVec<1, i16, 44>; // 1 x i16 vector value +def v2i16 : VTVec<2, i16, 45>; // 2 x i16 vector value +def v3i16 : VTVec<3, i16, 46>; // 3 x i16 vector value +def v4i16 : VTVec<4, i16, 47>; // 4 x i16 vector value +def v8i16 : VTVec<8, i16, 48>; // 8 x i16 vector value +def v16i16 : VTVec<16, i16, 49>; // 16 x i16 vector value +def v32i16 : VTVec<32, i16, 50>; // 32 x i16 vector value +def v64i16 : VTVec<64, i16, 51>; // 64 x i16 vector value +def v128i16 : VTVec<128, i16, 52>; // 128 x i16 vector value +def v256i16 : VTVec<256, i16, 53>; // 256 x i16 vector value +def v512i16 : VTVec<512, i16, 54>; // 512 x i16 vector value + +def v1i32 : VTVec<1, i32, 55>; // 1 x i32 vector value +def v2i32 : VTVec<2, i32, 56>; // 2 x i32 vector value +def v3i32 : VTVec<3, i32, 57>; // 3 x i32 vector value +def v4i32 : VTVec<4, i32, 58>; // 4 x i32 vector value +def v5i32 : VTVec<5, i32, 59>; // 5 x i32 vector value +def v6i32 : VTVec<6, i32, 60>; // 6 x f32 vector value +def v7i32 : VTVec<7, i32, 61>; // 7 x f32 vector value +def v8i32 : VTVec<8, i32, 62>; // 8 x i32 vector value +def v9i32 : VTVec<9, i32, 63>; // 9 x i32 vector value +def v10i32 : VTVec<10, i32, 64>; // 10 x i32 vector value +def v11i32 : VTVec<11, i32, 65>; // 11 x i32 vector value +def v12i32 : VTVec<12, i32, 66>; // 12 x i32 vector value +def v16i32 : VTVec<16, i32, 67>; // 16 x i32 vector value +def v32i32 : VTVec<32, i32, 68>; // 32 x i32 vector value +def v64i32 : VTVec<64, i32, 69>; // 64 x i32 vector value +def v128i32 : VTVec<128, i32, 70>; // 128 x i32 vector value +def v256i32 : VTVec<256, i32, 71>; // 256 x i32 vector value +def v512i32 : VTVec<512, i32, 72>; // 512 x i32 vector value +def v1024i32 : VTVec<1024, i32, 73>; // 1024 x i32 vector value +def v2048i32 : VTVec<2048, i32, 74>; // 2048 x i32 vector value + +def v1i64 : VTVec<1, i64, 75>; // 1 x i64 vector value +def v2i64 : VTVec<2, i64, 76>; // 2 x i64 vector value +def v3i64 : VTVec<3, i64, 77>; // 3 x i64 vector value +def v4i64 : VTVec<4, i64, 78>; // 4 x i64 vector value +def v8i64 : VTVec<8, i64, 79>; // 8 x i64 vector value +def v16i64 : VTVec<16, i64, 80>; // 16 x i64 vector value +def v32i64 : VTVec<32, i64, 81>; // 32 x i64 vector value +def v64i64 : VTVec<64, i64, 82>; // 64 x i64 vector value +def v128i64 : VTVec<128, i64, 83>; // 128 x i64 vector value +def v256i64 : VTVec<256, i64, 84>; // 256 x i64 vector value + +def v1i128 : VTVec<1, i128, 85>; // 1 x i128 vector value + +def v1f16 : VTVec<1, f16, 86>; // 1 x f16 vector value +def v2f16 : VTVec<2, f16, 87>; // 2 x f16 vector value +def v3f16 : VTVec<3, f16, 88>; // 3 x f16 vector value +def v4f16 : VTVec<4, f16, 89>; // 4 x f16 vector value +def v8f16 : VTVec<8, f16, 90>; // 8 x f16 vector value +def v16f16 : VTVec<16, f16, 91>; // 16 x f16 vector value +def v32f16 : VTVec<32, f16, 92>; // 32 x f16 vector value +def v64f16 : VTVec<64, f16, 93>; // 64 x f16 vector value +def v128f16 : VTVec<128, f16, 94>; // 128 x f16 vector value +def v256f16 : VTVec<256, f16, 95>; // 256 x f16 vector value +def v512f16 : VTVec<512, f16, 96>; // 512 x f16 vector value + +def v2bf16 : VTVec<2, bf16, 97>; // 2 x bf16 vector value +def v3bf16 : VTVec<3, bf16, 98>; // 3 x bf16 vector value +def v4bf16 : VTVec<4, bf16, 99>; // 4 x bf16 vector value +def v8bf16 : VTVec<8, bf16, 100>; // 8 x bf16 vector value +def v16bf16 : VTVec<16, bf16, 101>; // 16 x bf16 vector value +def v32bf16 : VTVec<32, bf16, 102>; // 32 x bf16 vector value +def v64bf16 : VTVec<64, bf16, 103>; // 64 x bf16 vector value +def v128bf16 : VTVec<128, bf16, 104>; // 128 x bf16 vector value + +def v1f32 : VTVec<1, f32, 105>; // 1 x f32 vector value +def v2f32 : VTVec<2, f32, 106>; // 2 x f32 vector value +def v3f32 : VTVec<3, f32, 107>; // 3 x f32 vector value +def v4f32 : VTVec<4, f32, 108>; // 4 x f32 vector value +def v5f32 : VTVec<5, f32, 109>; // 5 x f32 vector value +def v6f32 : VTVec<6, f32, 110>; // 6 x f32 vector value +def v7f32 : VTVec<7, f32, 111>; // 7 x f32 vector value +def v8f32 : VTVec<8, f32, 112>; // 8 x f32 vector value +def v9f32 : VTVec<9, f32, 113>; // 9 x f32 vector value +def v10f32 : VTVec<10, f32, 114>; // 10 x f32 vector value +def v11f32 : VTVec<11, f32, 115>; // 11 x f32 vector value +def v12f32 : VTVec<12, f32, 116>; // 12 x f32 vector value +def v16f32 : VTVec<16, f32, 117>; // 16 x f32 vector value +def v32f32 : VTVec<32, f32, 118>; // 32 x f32 vector value +def v64f32 : VTVec<64, f32, 119>; // 64 x f32 vector value +def v128f32 : VTVec<128, f32, 120>; // 128 x f32 vector value +def v256f32 : VTVec<256, f32, 121>; // 256 x f32 vector value +def v512f32 : VTVec<512, f32, 122>; // 512 x f32 vector value +def v1024f32 : VTVec<1024, f32, 123>; // 1024 x f32 vector value +def v2048f32 : VTVec<2048, f32, 124>; // 2048 x f32 vector value + +def v1f64 : VTVec<1, f64, 125>; // 1 x f64 vector value +def v2f64 : VTVec<2, f64, 126>; // 2 x f64 vector value +def v3f64 : VTVec<3, f64, 127>; // 3 x f64 vector value +def v4f64 : VTVec<4, f64, 128>; // 4 x f64 vector value +def v8f64 : VTVec<8, f64, 129>; // 8 x f64 vector value +def v16f64 : VTVec<16, f64, 130>; // 16 x f64 vector value +def v32f64 : VTVec<32, f64, 131>; // 32 x f64 vector value +def v64f64 : VTVec<64, f64, 132>; // 64 x f64 vector value +def v128f64 : VTVec<128, f64, 133>; // 128 x f64 vector value +def v256f64 : VTVec<256, f64, 134>; // 256 x f64 vector value + +def nxv1i1 : VTScalableVec<1, i1, 135>; // n x 1 x i1 vector value +def nxv2i1 : VTScalableVec<2, i1, 136>; // n x 2 x i1 vector value +def nxv4i1 : VTScalableVec<4, i1, 137>; // n x 4 x i1 vector value +def nxv8i1 : VTScalableVec<8, i1, 138>; // n x 8 x i1 vector value +def nxv16i1 : VTScalableVec<16, i1, 139>; // n x 16 x i1 vector value +def nxv32i1 : VTScalableVec<32, i1, 140>; // n x 32 x i1 vector value +def nxv64i1 : VTScalableVec<64, i1, 141>; // n x 64 x i1 vector value + +def nxv1i8 : VTScalableVec<1, i8, 142>; // n x 1 x i8 vector value +def nxv2i8 : VTScalableVec<2, i8, 143>; // n x 2 x i8 vector value +def nxv4i8 : VTScalableVec<4, i8, 144>; // n x 4 x i8 vector value +def nxv8i8 : VTScalableVec<8, i8, 145>; // n x 8 x i8 vector value +def nxv16i8 : VTScalableVec<16, i8, 146>; // n x 16 x i8 vector value +def nxv32i8 : VTScalableVec<32, i8, 147>; // n x 32 x i8 vector value +def nxv64i8 : VTScalableVec<64, i8, 148>; // n x 64 x i8 vector value + +def nxv1i16 : VTScalableVec<1, i16, 149>; // n x 1 x i16 vector value +def nxv2i16 : VTScalableVec<2, i16, 150>; // n x 2 x i16 vector value +def nxv4i16 : VTScalableVec<4, i16, 151>; // n x 4 x i16 vector value +def nxv8i16 : VTScalableVec<8, i16, 152>; // n x 8 x i16 vector value +def nxv16i16 : VTScalableVec<16, i16, 153>; // n x 16 x i16 vector value +def nxv32i16 : VTScalableVec<32, i16, 154>; // n x 32 x i16 vector value + +def nxv1i32 : VTScalableVec<1, i32, 155>; // n x 1 x i32 vector value +def nxv2i32 : VTScalableVec<2, i32, 156>; // n x 2 x i32 vector value +def nxv4i32 : VTScalableVec<4, i32, 157>; // n x 4 x i32 vector value +def nxv8i32 : VTScalableVec<8, i32, 158>; // n x 8 x i32 vector value +def nxv16i32 : VTScalableVec<16, i32, 159>; // n x 16 x i32 vector value +def nxv32i32 : VTScalableVec<32, i32, 160>; // n x 32 x i32 vector value + +def nxv1i64 : VTScalableVec<1, i64, 161>; // n x 1 x i64 vector value +def nxv2i64 : VTScalableVec<2, i64, 162>; // n x 2 x i64 vector value +def nxv4i64 : VTScalableVec<4, i64, 163>; // n x 4 x i64 vector value +def nxv8i64 : VTScalableVec<8, i64, 164>; // n x 8 x i64 vector value +def nxv16i64 : VTScalableVec<16, i64, 165>; // n x 16 x i64 vector value +def nxv32i64 : VTScalableVec<32, i64, 166>; // n x 32 x i64 vector value + +def nxv1f16 : VTScalableVec<1, f16, 167>; // n x 1 x f16 vector value +def nxv2f16 : VTScalableVec<2, f16, 168>; // n x 2 x f16 vector value +def nxv4f16 : VTScalableVec<4, f16, 169>; // n x 4 x f16 vector value +def nxv8f16 : VTScalableVec<8, f16, 170>; // n x 8 x f16 vector value +def nxv16f16 : VTScalableVec<16, f16, 171>; // n x 16 x f16 vector value +def nxv32f16 : VTScalableVec<32, f16, 172>; // n x 32 x f16 vector value + +def nxv1bf16 : VTScalableVec<1, bf16, 173>; // n x 1 x bf16 vector value +def nxv2bf16 : VTScalableVec<2, bf16, 174>; // n x 2 x bf16 vector value +def nxv4bf16 : VTScalableVec<4, bf16, 175>; // n x 4 x bf16 vector value +def nxv8bf16 : VTScalableVec<8, bf16, 176>; // n x 8 x bf16 vector value +def nxv16bf16 : VTScalableVec<16, bf16, 177>; // n x 16 x bf16 vector value +def nxv32bf16 : VTScalableVec<32, bf16, 178>; // n x 32 x bf16 vector value + +def nxv1f32 : VTScalableVec<1, f32, 179>; // n x 1 x f32 vector value +def nxv2f32 : VTScalableVec<2, f32, 180>; // n x 2 x f32 vector value +def nxv4f32 : VTScalableVec<4, f32, 181>; // n x 4 x f32 vector value +def nxv8f32 : VTScalableVec<8, f32, 182>; // n x 8 x f32 vector value +def nxv16f32 : VTScalableVec<16, f32, 183>; // n x 16 x f32 vector value + +def nxv1f64 : VTScalableVec<1, f64, 184>; // n x 1 x f64 vector value +def nxv2f64 : VTScalableVec<2, f64, 185>; // n x 2 x f64 vector value +def nxv4f64 : VTScalableVec<4, f64, 186>; // n x 4 x f64 vector value +def nxv8f64 : VTScalableVec<8, f64, 187>; // n x 8 x f64 vector value def x86mmx : ValueType<64, 188>; // X86 MMX value def FlagVT : ValueType<0, 189>; // Pre-RA sched glue @@ -244,22 +282,24 @@ // Pseudo valuetype mapped to the current pointer size to any address space. // Should only be used in TableGen. -def iPTRAny : ValueType<0, 250>; +def iPTRAny : VTAny<250>; // Pseudo valuetype to represent "vector of any size" -def vAny : ValueType<0, 251>; +def vAny : VTAny<251>; // Pseudo valuetype to represent "float of any format" -def fAny : ValueType<0, 252>; +def fAny : VTAny<252>; // Pseudo valuetype to represent "integer of any bit width" -def iAny : ValueType<0, 253>; +def iAny : VTAny<253>; // Pseudo valuetype mapped to the current pointer size. def iPTR : ValueType<0, 254>; // Pseudo valuetype to represent "any type of any size". -def Any : ValueType<0, 255>; +def Any : VTAny<255>; + +} // end defset ValueTypes /// This class is for targets that want to use pointer types in patterns /// with the GlobalISelEmitter. Targets must define their own pointer diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h --- a/llvm/include/llvm/IR/Intrinsics.h +++ b/llvm/include/llvm/IR/Intrinsics.h @@ -149,13 +149,11 @@ ElementCount Vector_Width; }; + // AK_% : Defined in Intrinsics.td enum ArgKind { - AK_Any, - AK_AnyInteger, - AK_AnyFloat, - AK_AnyVector, - AK_AnyPointer, - AK_MatchType = 7 +#define GET_INTRINSIC_ARGKIND +#include "llvm/IR/IntrinsicEnums.inc" +#undef GET_INTRINSIC_ARGKIND }; unsigned getArgumentNumber() const { diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -167,29 +167,242 @@ // defined by the hasSideEffects property of the TableGen Instruction class. def IntrHasSideEffects : IntrinsicProperty; +//===----------------------------------------------------------------------===// +// IIT constants and utils +//===----------------------------------------------------------------------===// + +// llvm::Intrinsic::IITDescriptor::ArgKind::AK_% +def ArgKind { + int Any = 0; + int AnyInteger = 1; + int AnyFloat = 2; + int AnyVector = 3; + int AnyPointer = 4; + + int MatchType = 7; +} + +// (Idx << 3) | ArgCode +class EncAnyType { + int ret = !or(0x100, ArgCode); +} + +// (Mapping[Num] << 3) | MatchType +class EncMatchType { + int ret = !or(0x200, Num); +} + +// (Mapping[Num] << 3) | ArgCodes[Mapping[Num]] +class EncSameWidth { + int ret = !or(0x300, Num); +} + +// ArgNo +class EncNextArgA { + int ret = !or(0x400, dummy); +} + +// Mapping[Num] +class EncNextArgN { + int ret = !or(0x500, Num); +} + +class DecArgCode< + list Mapping, + list ArgCodes, + int ACIdx, + int ax +> { + int ah = !and(ax, 0xFF00); + int al = !and(ax, 0x00FF); + int num = Mapping[al]; + int ret = !cond( + !eq(ah, EncAnyType<>.ret) : !or(!shl(ACIdx, 3), al), + !eq(ah, EncMatchType<>.ret) : !or(!shl(num, 3), ArgKind.MatchType), + !eq(ah, EncSameWidth<>.ret) : !or(!shl(num, 3), ArgCodes[num]), + !eq(ah, EncNextArgA<>.ret) : ACIdx, + !eq(ah, EncNextArgN<>.ret) : num, + true : al); +} + +//===----------------------------------------------------------------------===// +// IIT_Info +//===----------------------------------------------------------------------===// + +class IIT_Base { + int Number = num; + list VTs = ?; +} + +class IIT_VT : IIT_Base { + let VTs = [vt]; +} + +class IIT_Int : IIT_Base { + let VTs = !filter(vti, ValueTypes, + !and(vti.isInteger, !eq(vti.Size, size))); +} + +class IIT_Vec : IIT_Base { + let VTs = !filter(vti, ValueTypes, + !and(vti.isVector, !eq(vti.nElem, nelem))); +} + +defset list IIT_all = { +def IIT_Done : IIT_Base< 0>; +def IIT_I1 : IIT_Int<1, 1>; +def IIT_I8 : IIT_Int<8, 2>; +def IIT_I16 : IIT_Int<16, 3>; +def IIT_I32 : IIT_Int<32, 4>; +def IIT_I64 : IIT_Int<64, 5>; +def IIT_F16 : IIT_VT; +def IIT_F32 : IIT_VT; +def IIT_F64 : IIT_VT; +def IIT_V2 : IIT_Vec<2, 9>; +def IIT_V4 : IIT_Vec<4, 10>; +def IIT_V8 : IIT_Vec<8, 11>; +def IIT_V16 : IIT_Vec<16, 12>; +def IIT_V32 : IIT_Vec<32, 13>; +def IIT_PTR : IIT_Base< 14>; +def IIT_ARG : IIT_Base< 15>; + +def IIT_V64 : IIT_Vec<64, 16>; +def IIT_MMX : IIT_VT; +def IIT_TOKEN : IIT_VT; +def IIT_METADATA : IIT_VT; +def IIT_EMPTYSTRUCT : IIT_VT; +def IIT_STRUCT2 : IIT_Base<21>; +def IIT_STRUCT3 : IIT_Base<22>; +def IIT_STRUCT4 : IIT_Base<23>; +def IIT_STRUCT5 : IIT_Base<24>; +def IIT_EXTEND_ARG : IIT_Base<25>; +def IIT_TRUNC_ARG : IIT_Base<26>; +def IIT_ANYPTR : IIT_Base<27>; +def IIT_V1 : IIT_Vec<1, 28>; +def IIT_VARARG : IIT_VT; +def IIT_HALF_VEC_ARG : IIT_Base<30>; +def IIT_SAME_VEC_WIDTH_ARG : IIT_Base<31>; +def IIT_PTR_TO_ARG : IIT_Base<32>; +def IIT_PTR_TO_ELT : IIT_Base<33>; +def IIT_VEC_OF_ANYPTRS_TO_ELT : IIT_Base<34>; +def IIT_I128 : IIT_Int<128, 35>; +def IIT_V512 : IIT_Vec<512, 36>; +def IIT_V1024 : IIT_Vec<1024, 37>; +def IIT_STRUCT6 : IIT_Base<38>; +def IIT_STRUCT7 : IIT_Base<39>; +def IIT_STRUCT8 : IIT_Base<40>; +def IIT_F128 : IIT_VT; +def IIT_VEC_ELEMENT : IIT_Base<42>; +def IIT_SCALABLE_VEC : IIT_Base<43>; +def IIT_SUBDIVIDE2_ARG : IIT_Base<44>; +def IIT_SUBDIVIDE4_ARG : IIT_Base<45>; +def IIT_VEC_OF_BITCASTS_TO_INT : IIT_Base<46>; +def IIT_V128 : IIT_Vec<128, 47>; +def IIT_BF16 : IIT_VT; +def IIT_STRUCT9 : IIT_Base<49>; +def IIT_V256 : IIT_Vec<256, 50>; +def IIT_AMX : IIT_VT; +def IIT_PPCF128 : IIT_VT; +def IIT_V3 : IIT_Vec<3, 53>; +def IIT_EXTERNREF : IIT_VT; +def IIT_FUNCREF : IIT_VT; +def IIT_ANYPTR_TO_ELT : IIT_Base<56>; +def IIT_I2 : IIT_Int<2, 57>; +def IIT_I4 : IIT_Int<4, 58>; +} + +defvar IIT_all_FixedTypes = !filter(iit, IIT_all, + !or(!isa(iit), !isa(iit))); + +defvar IIT_all_VectorTypes = !filter(iit, IIT_all, + !isa(iit)); + +defvar IIT_RetNumbers = [ + [IIT_Done.Number], + [], + [IIT_STRUCT2.Number], + [IIT_STRUCT3.Number], + [IIT_STRUCT4.Number], + [IIT_STRUCT5.Number], + [IIT_STRUCT6.Number], + [IIT_STRUCT7.Number], + [IIT_STRUCT8.Number], + [IIT_STRUCT9.Number], +]; + //===----------------------------------------------------------------------===// // Types used by intrinsics. //===----------------------------------------------------------------------===// class LLVMType { ValueType VT = vt; - int isAny = false; + int isAny = vt.isOverloaded; + + int ArgCode = ?; + int Number = ?; + + list IITs = !filter(iit, IIT_all_FixedTypes, + !not(!empty(!filter(iit_vt, iit.VTs, + !eq(iit_vt, !if(vt.isVector, vt.ElementType, vt)))))); + assert !le(!size(IITs), 1), "Duplicate type"; + + list IIT_Vecs = !if(vt.isVector, + !filter(iit, IIT_all_VectorTypes, + !not(!empty(!filter(iit_vt, iit.VTs, !and( + !eq(iit_vt.ElementType, vt.ElementType), + !eq(iit_vt.nElem, vt.nElem)))))), + []); + assert !le(!size(IIT_Vecs), 1), "Duplicate type"; + + list Sig = !listconcat( + !if(vt.isScalable, [IIT_SCALABLE_VEC.Number], []), + !foreach(iit, IIT_Vecs, iit.Number), + !foreach(iit, IITs, iit.Number)); +} + +class LLVMAnyType : LLVMType { + let ArgCode = !cond( + !eq(vt, Any) : ArgKind.Any, + !eq(vt, iAny) : ArgKind.AnyInteger, + !eq(vt, fAny) : ArgKind.AnyFloat, + !eq(vt, vAny) : ArgKind.AnyVector, + !eq(vt, iPTRAny) : ArgKind.AnyPointer, + ); + let Sig = [ + IIT_ARG.Number, + EncAnyType.ret, + ]; + + assert isAny, "LLVMAnyType.VT should have isOverloaded"; } class LLVMQualPointerType : LLVMType{ LLVMType ElTy = elty; - int AddrSpace = addrspace; + assert !and(!le(0, addrspace), !le(addrspace, 255)), + "Address space exceeds 255"; + + // D63507: LLVMPointerType + let isAny = elty.isAny; + + let Sig = !listconcat( + !if(addrspace, [ + IIT_ANYPTR.Number, + addrspace, + ], [ + IIT_PTR.Number, + ]), + ElTy.Sig); } class LLVMPointerType : LLVMQualPointerType; class LLVMAnyPointerType - : LLVMType{ + : LLVMAnyType { LLVMType ElTy = elty; - let isAny = true; + assert isAny, "iPTRAny should have isOverloaded"; } // Match the type of another intrinsic parameter. Number is an index into the @@ -198,53 +411,75 @@ // Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_anyfloat_ty, LLVMMatchType<0>]> // has two overloaded types, the 2nd and 3rd arguments. LLVMMatchType<0> // refers to the first overloaded type, which is the 2nd argument. -class LLVMMatchType +class LLVMMatchType : LLVMType{ - int Number = num; + let Number = num; + let Sig = [ + IIT_Info.Number, + EncMatchType.ret, + ]; +} + +class LLVMMatchTypeNextArg + : LLVMMatchType { + let Sig = [ + IIT_Info.Number, + EncNextArgA<>.ret, + EncNextArgN.ret, + ]; } // Match the type of another intrinsic parameter that is expected to be based on // an integral type (i.e. either iN or ), but change the scalar size to // be twice as wide or half as wide as the other type. This is only useful when // the intrinsic is overloaded, so the matched type should be declared as iAny. -class LLVMExtendedType : LLVMMatchType; -class LLVMTruncatedType : LLVMMatchType; +class LLVMExtendedType : LLVMMatchType; +class LLVMTruncatedType : LLVMMatchType; // Match the scalar/vector of another intrinsic parameter but with a different // element type. Either both are scalars or both are vectors with the same // number of elements. class LLVMScalarOrSameVectorWidth - : LLVMMatchType { - ValueType ElTy = elty.VT; + : LLVMMatchType { + let Sig = !listconcat([ + IIT_SAME_VEC_WIDTH_ARG.Number, + EncSameWidth.ret, + ], elty.Sig); } -class LLVMPointerTo : LLVMMatchType; -class LLVMPointerToElt : LLVMMatchType; -class LLVMAnyPointerToElt : LLVMMatchType; -class LLVMVectorOfAnyPointersToElt : LLVMMatchType; -class LLVMVectorElementType : LLVMMatchType; +class LLVMPointerTo : LLVMMatchType; +class LLVMPointerToElt : LLVMMatchType; +class LLVMAnyPointerToElt + : LLVMMatchTypeNextArg; +class LLVMVectorOfAnyPointersToElt + : LLVMMatchTypeNextArg; +class LLVMVectorElementType : LLVMMatchType; // Match the type of another intrinsic parameter that is expected to be a // vector type, but change the element count to be half as many. -class LLVMHalfElementsVectorType : LLVMMatchType; +class LLVMHalfElementsVectorType + : LLVMMatchType; // Match the type of another intrinsic parameter that is expected to be a // vector type (i.e. ) but with each element subdivided to // form a vector with more elements that are smaller than the original. -class LLVMSubdivide2VectorType : LLVMMatchType; -class LLVMSubdivide4VectorType : LLVMMatchType; +class LLVMSubdivide2VectorType + : LLVMMatchType; +class LLVMSubdivide4VectorType + : LLVMMatchType; // Match the element count and bit width of another intrinsic parameter, but // change the element type to an integer. -class LLVMVectorOfBitcastsToInt : LLVMMatchType; +class LLVMVectorOfBitcastsToInt + : LLVMMatchType; def llvm_void_ty : LLVMType; -let isAny = true in { - def llvm_any_ty : LLVMType; - def llvm_anyint_ty : LLVMType; - def llvm_anyfloat_ty : LLVMType; - def llvm_anyvector_ty : LLVMType; -} + +def llvm_any_ty : LLVMAnyType; +def llvm_anyint_ty : LLVMAnyType; +def llvm_anyfloat_ty : LLVMAnyType; +def llvm_anyvector_ty : LLVMAnyType; + def llvm_i1_ty : LLVMType; def llvm_i8_ty : LLVMType; def llvm_i16_ty : LLVMType; @@ -348,6 +583,57 @@ def llvm_externref_ty : LLVMType; def llvm_funcref_ty : LLVMType; +//===----------------------------------------------------------------------===// + +class MakeIdx Set> { + list IdxsR = !foreach(i, !range(Set), + !if(Set[i], + !foldl(0, !range(0, i), m, j, !add(m, Set[j])), + -1)); + + list RIdxsR = !foreach(i, !range(Set), + !foldl(-1, !range(Set), m, j, + !if(!and(Set[j], !eq(IdxsR[j], i)), j, m))); + + list Idxs = !foreach(a, IdxsR, !if(!ge(a, 0), a, ?)); + list RIdxs = !foreach(a, RIdxsR, !if(!ge(a, 0), a, ?)); +} + +class TypeInfoGen< + list RetTypes, + list ParamTypes +> { + list AllTypes = !listconcat(RetTypes, ParamTypes); + + // ArgCodes for NextArg -- isAny or MatchTypeNextArg + list ACIdxs = MakeIdx< + !foreach(ty, AllTypes, + !or(ty.isAny, !isa(ty)))>.Idxs; + + // ArgCodes (only for isAny or MatchTypeNextArg) + list ACTys = !filter(ty, AllTypes, + !or(ty.isAny, !isa(ty))); + + list ArgCodes = !foreach(ty, ACTys, ty.ArgCode); + + // Mappings MatchTypeIdx to ACTys + list MappingRIdxs = MakeIdx< + !foreach(ty, ACTys, ty.isAny)>.RIdxs; + + list Types = !foreach(ty, AllTypes, + !if(!isa(ty), ACTys[MappingRIdxs[ty.Number]], ty)); + + list> TypeSig = !listconcat( + [IIT_RetNumbers[!size(RetTypes)]], + !foreach(i, !range(AllTypes), + !foreach(a, AllTypes[i].Sig, + DecArgCode< + MappingRIdxs, + ArgCodes, + ACIdxs[i], + a>.ret))); +} + //===----------------------------------------------------------------------===// // Intrinsic Definitions. //===----------------------------------------------------------------------===// @@ -381,6 +667,11 @@ bit DisableDefaultAttributes = disable_default_attributes; bit isTarget = false; + + TypeInfoGen TypeInfo = TypeInfoGen; + bit isOverloaded = !gt(!size(TypeInfo.MappingRIdxs), 0); + list Types = TypeInfo.Types; + list> TypeSig = TypeInfo.TypeSig; } // Intrinsic with default attributes (disable_default_attributes = false). @@ -404,6 +695,7 @@ string MSBuiltinName = name; } +#ifndef TEST_INTRINSICS_SUPPRESS_DEFS //===--------------- Variable Argument Handling Intrinsics ----------------===// // @@ -2203,3 +2495,5 @@ include "llvm/IR/IntrinsicsVE.td" include "llvm/IR/IntrinsicsDirectX.td" include "llvm/IR/IntrinsicsLoongArch.td" + +#endif // TEST_INTRINSICS_SUPPRESS_DEFS diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -316,7 +316,6 @@ IK_AnonymousNameInit, IK_StringInit, IK_VarInit, - IK_VarListElementInit, IK_VarBitInit, IK_VarDefInit, IK_LastTypedInit, @@ -386,14 +385,6 @@ return nullptr; } - /// This function is used to implement the list slice - /// selection operator. Given a value, it selects the specified list - /// elements, returning them as a new \p Init of type \p list. If it - /// is not legal to use the slice operator, null is returned. - virtual Init *convertInitListSlice(ArrayRef Elements) const { - return nullptr; - } - /// This function is used to implement the FieldInit class. /// Implementors of this method should return the type of the named /// field if they are of type record. @@ -445,7 +436,6 @@ Init *convertInitializerTo(RecTy *Ty) const override; Init *convertInitializerBitRange(ArrayRef Bits) const override; - Init *convertInitListSlice(ArrayRef Elements) const override; /// This method is used to implement the FieldInit class. /// Implementors of this method should return the type of the named field if @@ -726,8 +716,6 @@ Record *getElementAsRecord(unsigned i) const; - Init *convertInitListSlice(ArrayRef Elements) const override; - Init *convertInitializerTo(RecTy *Ty) const override; /// This method is used by classes that refer to other @@ -859,6 +847,10 @@ LISTCONCAT, LISTSPLAT, LISTREMOVE, + LISTELEM, + LISTSLICE, + RANGE, + RANGEC, STRCONCAT, INTERLEAVE, CONCAT, @@ -1240,39 +1232,6 @@ } }; -/// List[4] - Represent access to one element of a var or -/// field. -class VarListElementInit : public TypedInit { - TypedInit *TI; - unsigned Element; - - VarListElementInit(TypedInit *T, unsigned E) - : TypedInit(IK_VarListElementInit, - cast(T->getType())->getElementType()), - TI(T), Element(E) { - assert(T->getType() && isa(T->getType()) && - "Illegal VarBitInit expression!"); - } - -public: - VarListElementInit(const VarListElementInit &) = delete; - VarListElementInit &operator=(const VarListElementInit &) = delete; - - static bool classof(const Init *I) { - return I->getKind() == IK_VarListElementInit; - } - - static VarListElementInit *get(TypedInit *T, unsigned E); - - TypedInit *getVariable() const { return TI; } - unsigned getElementNum() const { return Element; } - - std::string getAsString() const override; - Init *resolveReferences(Resolver &R) const override; - - Init *getBit(unsigned Bit) const override; -}; - /// AL - Represent a reference to a 'def' in the description class DefInit : public TypedInit { friend class Record; @@ -1999,17 +1958,19 @@ /// Get all the concrete records that inherit from the one specified /// class. The class must be defined. - std::vector getAllDerivedDefinitions(StringRef ClassName) const; + std::vector getAllDerivedDefinitions(StringRef ClassName, + bool SortNumeric = true) const; /// Get all the concrete records that inherit from all the specified /// classes. The classes must be defined. - std::vector getAllDerivedDefinitions( - ArrayRef ClassNames) const; + std::vector getAllDerivedDefinitions(ArrayRef ClassNames, + bool SortNumeric = true) const; /// Get all the concrete records that inherit from specified class, if the /// class is defined. Returns an empty vector if the class is not defined. std::vector - getAllDerivedDefinitionsIfDefined(StringRef ClassName) const; + getAllDerivedDefinitionsIfDefined(StringRef ClassName, + bool SortNumeric = true) const; void dump() const; diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -1023,70 +1023,11 @@ /// IIT_Info - These are enumerators that describe the entries returned by the /// getIntrinsicInfoTableEntries function. /// -/// NOTE: This must be kept in synch with the copy in TblGen/IntrinsicEmitter! +/// Defined in Intrinsics.td. enum IIT_Info { - // Common values should be encoded with 0-15. - IIT_Done = 0, - IIT_I1 = 1, - IIT_I8 = 2, - IIT_I16 = 3, - IIT_I32 = 4, - IIT_I64 = 5, - IIT_F16 = 6, - IIT_F32 = 7, - IIT_F64 = 8, - IIT_V2 = 9, - IIT_V4 = 10, - IIT_V8 = 11, - IIT_V16 = 12, - IIT_V32 = 13, - IIT_PTR = 14, - IIT_ARG = 15, - - // Values from 16+ are only encodable with the inefficient encoding. - IIT_V64 = 16, - IIT_MMX = 17, - IIT_TOKEN = 18, - IIT_METADATA = 19, - IIT_EMPTYSTRUCT = 20, - IIT_STRUCT2 = 21, - IIT_STRUCT3 = 22, - IIT_STRUCT4 = 23, - IIT_STRUCT5 = 24, - IIT_EXTEND_ARG = 25, - IIT_TRUNC_ARG = 26, - IIT_ANYPTR = 27, - IIT_V1 = 28, - IIT_VARARG = 29, - IIT_HALF_VEC_ARG = 30, - IIT_SAME_VEC_WIDTH_ARG = 31, - IIT_PTR_TO_ARG = 32, - IIT_PTR_TO_ELT = 33, - IIT_VEC_OF_ANYPTRS_TO_ELT = 34, - IIT_I128 = 35, - IIT_V512 = 36, - IIT_V1024 = 37, - IIT_STRUCT6 = 38, - IIT_STRUCT7 = 39, - IIT_STRUCT8 = 40, - IIT_F128 = 41, - IIT_VEC_ELEMENT = 42, - IIT_SCALABLE_VEC = 43, - IIT_SUBDIVIDE2_ARG = 44, - IIT_SUBDIVIDE4_ARG = 45, - IIT_VEC_OF_BITCASTS_TO_INT = 46, - IIT_V128 = 47, - IIT_BF16 = 48, - IIT_STRUCT9 = 49, - IIT_V256 = 50, - IIT_AMX = 51, - IIT_PPCF128 = 52, - IIT_V3 = 53, - IIT_EXTERNREF = 54, - IIT_FUNCREF = 55, - IIT_ANYPTR_TO_ELT = 56, - IIT_I2 = 57, - IIT_I4 = 58, +#define GET_INTRINSIC_IITINFO +#include "llvm/IR/IntrinsicImpl.inc" +#undef GET_INTRINSIC_IITINFO }; static void DecodeIITType(unsigned &NextElt, ArrayRef Infos, diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -83,8 +83,6 @@ FoldingSet TheExistsOpInitPool; DenseMap, VarInit *> TheVarInitPool; DenseMap, VarBitInit *> TheVarBitInitPool; - DenseMap, VarListElementInit *> - TheVarListElementInitPool; FoldingSet TheVarDefInitPool; DenseMap, FieldInit *> TheFieldInitPool; FoldingSet TheCondOpInitPool; @@ -676,23 +674,6 @@ return nullptr; } -Init *ListInit::convertInitListSlice(ArrayRef Elements) const { - if (Elements.size() == 1) { - if (Elements[0] >= size()) - return nullptr; - return getElement(Elements[0]); - } - - SmallVector Vals; - Vals.reserve(Elements.size()); - for (unsigned Element : Elements) { - if (Element >= size()) - return nullptr; - Vals.push_back(getElement(Element)); - } - return ListInit::get(Vals, getElementType()); -} - Record *ListInit::getElementAsRecord(unsigned i) const { assert(i < NumValues && "List element index out of range!"); DefInit *DI = dyn_cast(getElement(i)); @@ -1206,6 +1187,69 @@ } break; } + case LISTELEM: { + auto *TheList = dyn_cast(LHS); + auto *Idx = dyn_cast(RHS); + if (TheList && Idx) { + auto i = Idx->getValue(); + if (0 <= i && i < (ssize_t)TheList->size()) + return TheList->getElement(i); + } + break; + } + case LISTSLICE: { + auto *TheList = dyn_cast(LHS); + auto *SliceIdxs = dyn_cast(RHS); + if (TheList && SliceIdxs) { + SmallVector Args; + Args.reserve(SliceIdxs->size()); + for (auto *I : *SliceIdxs) { + auto *II = dyn_cast(I); + if (!II) + goto listslice_fail; + auto i = II->getValue(); + if (!(0 <= i && i < (ssize_t)TheList->size())) + goto listslice_fail; + Args.push_back(TheList->getElement(i)); + } + return ListInit::get(Args, TheList->getElementType()); + } + listslice_fail: + break; + } + case RANGE: + case RANGEC: { + auto *LHSi = dyn_cast(LHS); + auto *RHSi = dyn_cast(RHS); + if (LHSi && RHSi) { + auto Start = LHSi->getValue(); + auto End = RHSi->getValue(); + SmallVector Args; + if (getOpcode() == RANGEC) { + // Closed interval + if (Start <= End) { + // Ascending order + Args.reserve(End - Start + 1); + for (auto i = Start; i <= End; ++i) + Args.push_back(IntInit::get(getRecordKeeper(), i)); + } else { + // Descending order + Args.reserve(Start - End + 1); + for (auto i = Start; i >= End; --i) + Args.push_back(IntInit::get(getRecordKeeper(), i)); + } + } else if (Start < End) { + // Half-open interval (excludes `End`) + Args.reserve(End - Start); + for (auto i = Start; i < End; ++i) + Args.push_back(IntInit::get(getRecordKeeper(), i)); + } else { + // Empty set + } + return ListInit::get(Args, LHSi->getType()); + } + break; + } case STRCONCAT: { StringInit *LHSs = dyn_cast(LHS); StringInit *RHSs = dyn_cast(RHS); @@ -1311,6 +1355,11 @@ std::string BinOpInit::getAsString() const { std::string Result; switch (getOpcode()) { + case LISTELEM: + case LISTSLICE: + return LHS->getAsString() + "[" + RHS->getAsString() + "]"; + case RANGEC: + return LHS->getAsString() + "..." + RHS->getAsString(); case CONCAT: Result = "!con"; break; case ADD: Result = "!add"; break; case SUB: Result = "!sub"; break; @@ -1331,6 +1380,7 @@ case LISTCONCAT: Result = "!listconcat"; break; case LISTSPLAT: Result = "!listsplat"; break; case LISTREMOVE: Result = "!listremove"; break; + case RANGE: Result = "!range"; break; case STRCONCAT: Result = "!strconcat"; break; case INTERLEAVE: Result = "!interleave"; break; case SETDAGOP: Result = "!setdagop"; break; @@ -1894,22 +1944,6 @@ ->Fold(nullptr); } -Init *TypedInit::convertInitListSlice(ArrayRef Elements) const { - ListRecTy *T = dyn_cast(getType()); - if (!T) return nullptr; // Cannot subscript a non-list variable. - - if (Elements.size() == 1) - return VarListElementInit::get(const_cast(this), Elements[0]); - - SmallVector ListInits; - ListInits.reserve(Elements.size()); - for (unsigned Element : Elements) - ListInits.push_back(VarListElementInit::get(const_cast(this), - Element)); - return ListInit::get(ListInits, T->getElementType()); -} - - VarInit *VarInit::get(StringRef VN, RecTy *T) { Init *Value = StringInit::get(T->getRecordKeeper(), VN); return VarInit::get(Value, T); @@ -1960,37 +1994,6 @@ return const_cast(this); } -VarListElementInit *VarListElementInit::get(TypedInit *T, unsigned E) { - detail::RecordKeeperImpl &RK = T->getRecordKeeper().getImpl(); - VarListElementInit *&I = RK.TheVarListElementInitPool[std::make_pair(T, E)]; - if (!I) - I = new (RK.Allocator) VarListElementInit(T, E); - return I; -} - -std::string VarListElementInit::getAsString() const { - return TI->getAsString() + "[" + utostr(Element) + "]"; -} - -Init *VarListElementInit::resolveReferences(Resolver &R) const { - Init *NewTI = TI->resolveReferences(R); - if (ListInit *List = dyn_cast(NewTI)) { - // Leave out-of-bounds array references as-is. This can happen without - // being an error, e.g. in the untaken "branch" of an !if expression. - if (getElementNum() < List->size()) - return List->getElement(getElementNum()); - } - if (NewTI != TI && isa(NewTI)) - return VarListElementInit::get(cast(NewTI), getElementNum()); - return const_cast(this); -} - -Init *VarListElementInit::getBit(unsigned Bit) const { - if (getType() == BitRecTy::get(getRecordKeeper())) - return const_cast(this); - return VarBitInit::get(const_cast(this), Bit); -} - DefInit::DefInit(Record *D) : TypedInit(IK_DefInit, D->getType()), Def(D) {} @@ -2976,18 +2979,21 @@ } std::vector -RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const { +RecordKeeper::getAllDerivedDefinitions(StringRef ClassName, + bool SortNumeric) const { // We cache the record vectors for single classes. Many backends request // the same vectors multiple times. auto Pair = ClassRecordsMap.try_emplace(ClassName); if (Pair.second) - Pair.first->second = getAllDerivedDefinitions(ArrayRef(ClassName)); + Pair.first->second = + getAllDerivedDefinitions(ArrayRef(ClassName), SortNumeric); return Pair.first->second; } -std::vector RecordKeeper::getAllDerivedDefinitions( - ArrayRef ClassNames) const { +std::vector +RecordKeeper::getAllDerivedDefinitions(ArrayRef ClassNames, + bool SortNumeric) const { SmallVector ClassRecs; std::vector Defs; @@ -3006,12 +3012,18 @@ Defs.push_back(OneDef.second.get()); } + if (SortNumeric) + llvm::sort(Defs, [](Record *LHS, Record *RHS) { + return LHS->getName().compare_numeric(RHS->getName()) < 0; + }); + return Defs; } std::vector -RecordKeeper::getAllDerivedDefinitionsIfDefined(StringRef ClassName) const { - return getClass(ClassName) ? getAllDerivedDefinitions(ClassName) +RecordKeeper::getAllDerivedDefinitionsIfDefined(StringRef ClassName, + bool SortNumeric) const { + return getClass(ClassName) ? getAllDerivedDefinitions(ClassName, SortNumeric) : std::vector(); } diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -56,7 +56,7 @@ XSHL, XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XFind, XCast, XSubst, XForEach, XFilter, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetDagOp, XGetDagOp, - XExists, XListRemove, XToLower, XToUpper, + XExists, XListRemove, XToLower, XToUpper, XRange, // Boolean literals. TrueVal, FalseVal, diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -585,6 +585,7 @@ .Case("listconcat", tgtok::XListConcat) .Case("listsplat", tgtok::XListSplat) .Case("listremove", tgtok::XListRemove) + .Case("range", tgtok::XRange) .Case("strconcat", tgtok::XStrConcat) .Case("interleave", tgtok::XInterleave) .Case("substr", tgtok::XSubstr) diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -265,6 +265,7 @@ Record *CurRec); bool ParseOptionalRangeList(SmallVectorImpl &Ranges); bool ParseOptionalBitList(SmallVectorImpl &Ranges); + TypedInit *ParseSliceElements(Record *CurRec, bool Single = false); void ParseRangeList(SmallVectorImpl &Result); bool ParseRangePiece(SmallVectorImpl &Ranges, TypedInit *FirstItem = nullptr); diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -709,6 +709,128 @@ return Result; } +/// ParseSliceElements - Parse subscripts in square brackets. +/// +/// SliceElements ::= ( SliceElement ',' )* SliceElement ','? +/// SliceElement ::= Value> +/// SliceElement ::= Value +/// SliceElement ::= Value '...' Value +/// SliceElement ::= Value '-' Value (deprecated) +/// SliceElement ::= Value INTVAL(Negative; deprecated) +/// +/// Returns ListRecTy by defaut. +/// Returns IntRecTy if; +/// - Single=true +/// - SliceElements is Value w/o trailing comma +/// +TypedInit *TGParser::ParseSliceElements(Record *CurRec, bool Single) { + TypedInit *CurVal = nullptr; + SmallVector LoV; // int + SmallVector LoL; // list + auto *IntTy = IntRecTy::get(Records); + + auto FlushLoV = [&] { + if (!LoV.empty()) { + LoL.push_back(ListInit::get(LoV, IntTy)); + LoV.clear(); + } + Single = false; + }; + + do { + if (CurVal) + LoV.push_back(CurVal); + + auto LHSLoc = Lex.getLoc(); + auto *LHS = ParseValue(CurRec); + if (!LHS) + return nullptr; + CurVal = dyn_cast(LHS); + assert(CurVal); + + TypedInit *RHS = nullptr; + switch (Lex.getCode()) { + case tgtok::dotdotdot: + case tgtok::minus: { // Deprecated + Lex.Lex(); // eat + auto RHSLoc = Lex.getLoc(); + RHS = dyn_cast(ParseValue(CurRec)); + if (!isa(RHS->getType())) { + Error(RHSLoc, "range should be int...int"); + return nullptr; + } + break; + } + case tgtok::IntVal: { // Deprecated "-num" + RHS = IntInit::get(Records, -Lex.getCurIntVal()); + if (dyn_cast(RHS)->getValue() < 0) { + TokError("invalid range, cannot be negative"); + return nullptr; + } + Lex.Lex(); // eat IntVal + break; + } + default: + break; + } + + if (RHS) { + // Closed-interval range ... + if (!isa(CurVal->getType())) { + Error(LHSLoc, "range should be int...int"); + return nullptr; + } + + FlushLoV(); + LoL.push_back(dyn_cast( + BinOpInit::get(BinOpInit::RANGEC, CurVal, RHS, IntTy->getListTy()) + ->Fold(CurRec))); + CurVal = nullptr; + } else { + // Single value (not a range) + if (auto *LHSTy = dyn_cast(CurVal->getType())) { + if (!isa(LHSTy->getElementType())) { + Error(LHSLoc, "should be list"); + return nullptr; + } + // list + FlushLoV(); + LoL.push_back(CurVal); + CurVal = nullptr; + } else if (isa(CurVal->getType())) { + // int -- `CurVal` will be added lazily. + } else { + Error(LHSLoc, "unhandled type in range"); + return nullptr; + } + } + + if (Lex.getCode() != tgtok::comma) + break; + + Lex.Lex(); // eat comma + Single = false; + } while (Lex.getCode() != tgtok::r_square); + + if (CurVal) { + if (Single) + return CurVal; + + LoV.push_back(CurVal); + } + + FlushLoV(); + + TypedInit *Result = nullptr; + for (auto *LE : LoL) { + Result = (Result ? dyn_cast(BinOpInit::getListConcat(Result, LE)) + : LE); + assert(Result); + } + + return Result; +} + /// ParseRangePiece - Parse a bit/value range. /// RangePiece ::= INTVAL /// RangePiece ::= INTVAL '...' INTVAL @@ -1217,6 +1339,7 @@ case tgtok::XListConcat: case tgtok::XListSplat: case tgtok::XListRemove: + case tgtok::XRange: case tgtok::XStrConcat: case tgtok::XInterleave: case tgtok::XSetDagOp: { // Value ::= !binop '(' Value ',' Value ')' @@ -1247,6 +1370,7 @@ case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break; case tgtok::XListRemove: Code = BinOpInit::LISTREMOVE; break; + case tgtok::XRange: Code = BinOpInit::RANGE; break; case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; case tgtok::XInterleave: Code = BinOpInit::INTERLEAVE; break; case tgtok::XSetDagOp: Code = BinOpInit::SETDAGOP; break; @@ -1295,6 +1419,10 @@ // We don't know the list type until we parse the first argument. ArgType = ItemType; break; + case tgtok::XRange: + Type = IntRecTy::get(Records)->getListTy(); + // ArgType may be either Int or List. + break; case tgtok::XStrConcat: Type = StringRecTy::get(Records); ArgType = StringRecTy::get(Records); @@ -1379,6 +1507,26 @@ return nullptr; } break; + case BinOpInit::RANGE: + if (InitList.size() == 1) { + if (isa(ArgType)) { + ArgType = nullptr; + break; + } else if (!isa(ArgType)) { + Error(InitLoc, + Twine("expected list or int, got value of type '") + + ArgType->getAsString() + "'"); + return nullptr; + } + } else { + if (isa(dyn_cast(InitList[1])->getType())) { + Error(InitLoc, + Twine("expected one list, got extra value of type '") + + ArgType->getAsString() + "'"); + return nullptr; + } + } + break; case BinOpInit::EQ: case BinOpInit::NE: if (!ArgType->typeIsConvertibleTo(IntRecTy::get(Records)) && @@ -1477,6 +1625,36 @@ if (Code == BinOpInit::LISTREMOVE) Type = ArgType; + if (Code == BinOpInit::RANGE) { + Init *LHS, *RHS; + auto *Arg0 = dyn_cast(InitList[0]); + switch (InitList.size()) { + case 1: + if (isa(Arg0->getType())) { + // (0, !size(arg)) + LHS = IntInit::get(Records, 0); + RHS = UnOpInit::get(UnOpInit::SIZE, Arg0, IntRecTy::get(Records)) + ->Fold(CurRec); + } else { + assert(isa(Arg0->getType())); + // (0, arg) + LHS = IntInit::get(Records, 0); + RHS = Arg0; + } + break; + case 2: + assert(isa(Arg0->getType())); + assert(isa(dyn_cast(InitList[1])->getType())); + LHS = Arg0; + RHS = InitList[1]; + break; + default: + Error(OpLoc, "expected at most two values of integer"); + return nullptr; + } + return BinOpInit::get(Code, LHS, RHS, Type)->Fold(CurRec); + } + // We allow multiple operands to associative operators like !strconcat as // shorthand for nesting them. if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT || @@ -2208,6 +2386,8 @@ /// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')' /// SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')' /// SimpleValue ::= LISTREMOVETOK '(' Value ',' Value ')' +/// SimpleValue ::= RANGE '(' Value ')' +/// SimpleValue ::= RANGE '(' Value ',' Value ')' /// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' /// SimpleValue ::= COND '(' [Value ':' Value,]+ ')' /// @@ -2510,6 +2690,7 @@ case tgtok::XListConcat: case tgtok::XListSplat: case tgtok::XListRemove: + case tgtok::XRange: case tgtok::XStrConcat: case tgtok::XInterleave: case tgtok::XSetDagOp: // Value ::= !binop '(' Value ',' Value ')' @@ -2532,7 +2713,7 @@ /// /// Value ::= SimpleValue ValueSuffix* /// ValueSuffix ::= '{' BitList '}' -/// ValueSuffix ::= '[' BitList ']' +/// ValueSuffix ::= '[' SliceElements ']' /// ValueSuffix ::= '.' ID /// Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { @@ -2571,12 +2752,30 @@ } case tgtok::l_square: { SMLoc SquareLoc = Lex.getLoc(); + + auto *LHS = dyn_cast(Result); + assert(LHS); + auto *LHSTy = dyn_cast(LHS->getType()); + if (!LHSTy) { + Error(SquareLoc, "Type '" + Twine(LHS->getType()->getAsString()) + + "' is invalid for list subscript"); + return nullptr; + } + Lex.Lex(); // eat the '[' - SmallVector Ranges; - ParseRangeList(Ranges); - if (Ranges.empty()) return nullptr; + TypedInit *RHS = ParseSliceElements(CurRec, /*Single=*/true); + if (!RHS) + return nullptr; + + if (isa(RHS->getType())) { + Result = + BinOpInit::get(BinOpInit::LISTSLICE, LHS, RHS, LHSTy)->Fold(CurRec); + } else { + Result = BinOpInit::get(BinOpInit::LISTELEM, LHS, RHS, + LHSTy->getElementType()) + ->Fold(CurRec); + } - Result = Result->convertInitListSlice(Ranges); if (!Result) { Error(SquareLoc, "Invalid range for list slice"); return nullptr; diff --git a/llvm/test/TableGen/ListSlices-fail.td b/llvm/test/TableGen/ListSlices-fail.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/ListSlices-fail.td @@ -0,0 +1,53 @@ +// Each RUN line is scattered. + +defvar list_int = [0, 1, 2, 3, 4, 5]; +defvar list_str = ["foo", "bar"]; +defvar str = "hoge"; + +#ifdef ERR0 +// RUN: not llvm-tblgen %s -DERR0 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR0 +// ERR0: [[FILE]]:[[@LINE+1]]:24: error: Unknown or reserved token when parsing a value +defvar errs = list_str[]; +#endif + +#ifdef ERR1 +// RUN: not llvm-tblgen %s -DERR1 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR1 +// ERR1: [[FILE]]:[[@LINE+1]]:24: error: Unknown or reserved token when parsing a value +defvar errs = list_str[,]; +#endif + +#ifdef ERR2 +// RUN: not llvm-tblgen %s -DERR2 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR2 +// ERR2: [[FILE]]:[[@LINE+1]]:24: error: should be list +defvar errs = list_str[list_str]; +#endif + +#ifdef ERR3 +// RUN: not llvm-tblgen %s -DERR3 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR3 +// ERR3: [[FILE]]:[[@LINE+1]]:24: error: range should be int...int +defvar errs = list_str[list_str...42]; +#endif + +#ifdef ERR4 +// RUN: not llvm-tblgen %s -DERR4 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR4 +// ERR4: [[FILE]]:[[@LINE+1]]:28: error: range should be int...int +defvar errs = list_str[0...list_str]; +#endif + +#ifdef ERR5 +// RUN: not llvm-tblgen %s -DERR5 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR5 +// ERR5: [[FILE]]:[[@LINE+1]]:24: error: unhandled type in range +defvar errs = list_str[str]; +#endif + +#ifdef ERR6 +// RUN: not llvm-tblgen %s -DERR6 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR6 +// ERR6: [[FILE]]:[[@LINE+1]]:26: error: invalid range, cannot be negative +defvar errs = list_str[5 1]; +#endif + +#ifdef ERR7 +// RUN: not llvm-tblgen %s -DERR7 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR7 +// ERR7: [[FILE]]:[[@LINE+1]]:18: error: Type 'string' is invalid for list subscript +defvar errs = str[0]; +#endif diff --git a/llvm/test/TableGen/ListSlices.td b/llvm/test/TableGen/ListSlices.td --- a/llvm/test/TableGen/ListSlices.td +++ b/llvm/test/TableGen/ListSlices.td @@ -123,3 +123,42 @@ int Zero = Class1<[?, ?, 2, 3, ?, 5, ?]>.Zero; list TwoFive = Class1<[?, ?, 2, 3, ?, 5, ?]>.TwoFive; } + +// Test list[list] and list[int] +// CHECK: def Rec11 +def Rec11 { + list s5 = Var1[0...4]; + + // list[expr] + // CHECK: list rev = [4, 3, 2, 1, 0]; + list rev = !foreach(i, s5, Var1[!sub(4, i)]); + + // Slice by list[foreach] + // CHECK: list revf = [4, 3, 2, 1, 0]; + list revf = Var1[!foreach(i, s5, !sub(4, i))]; + + // Simple slice + // CHECK: list rr = [0, 1, 2, 3, 4]; + list rr = rev[rev]; + + // Trailing comma is acceptable + // CHECK: list rr_ = [0, 1, 2, 3, 4]; + list rr_ = rev[rev,]; + + // Concatenation in slice + // CHECK: list rrr = [1, 2, 4, 3, 2, 1, 0, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 8]; + list empty = []; + list rrr = Var1[1, 2, rev, 3...6, 7, empty, rr, 8]; + + // Recognized as slice by the trailing comma + // CHECK: list> rl1 = {{\[}}[0], [1], [2], [3], [4]]; + list> rl1 = !foreach(i, rev, rev[i,]); + + // Slice by pair + // CHECK: list> rll = {{\[}}[0, 4], [1, 3], [2, 2], [3, 1], [4, 0]]; + list> rll = !foreach(i, rev, rev[i, !sub(4, i)]); + + // Slice by dynamic range + // CHECK: list> rlr = {{\[}}[4, 3, 2, 1, 0], [3, 2, 1], [2], [1, 2, 3], [0, 1, 2, 3, 4]]; + list> rlr = !foreach(i, s5, rev[i...!sub(4, i)]); +} diff --git a/llvm/test/TableGen/intrinsic-pointer-to-any.td b/llvm/test/TableGen/intrinsic-pointer-to-any.td --- a/llvm/test/TableGen/intrinsic-pointer-to-any.td +++ b/llvm/test/TableGen/intrinsic-pointer-to-any.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen -gen-intrinsic-impl %s | FileCheck %s +// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS | FileCheck %s // This test is validating that it an Intrinsic with an LLVMPointerType to // llvm_any_ty still properly work after r363233. That patch rewrote the @@ -6,52 +6,7 @@ // case, so TableGen would hit an assertion in EncodeFixedType that was checking // to ensure that the substitution being processed was correctly replaced. -class IntrinsicProperty { - bit IsDefault = is_default; -} - -class SDNodeProperty; - -class ValueType { - string Namespace = "MVT"; - int Size = size; - int Value = value; -} - -def iPTR : ValueType<0 , 254>; -def Any : ValueType<0 , 255>; - -class LLVMType { - ValueType VT = vt; - int isAny = 0; -} - - -class Intrinsic ret_types> { - string LLVMName = ""; - string TargetPrefix = ""; // Set to a prefix for target-specific intrinsics. - list RetTypes = ret_types; - list ParamTypes = []; - list IntrProperties = []; - list Properties = []; - bit isTarget = 0; - bit DisableDefaultAttributes = 1; -} - -class LLVMQualPointerType - : LLVMType{ - LLVMType ElTy = elty; - int AddrSpace = 0; -} - -class LLVMPointerType - : LLVMQualPointerType; - -let isAny = 1 in { - def llvm_any_ty : LLVMType; -} -def i8 : ValueType<8, 3>; -def llvm_i8_ty : LLVMType; +include "llvm/IR/Intrinsics.td" def int_has_ptr_to_any : Intrinsic<[LLVMPointerType, llvm_i8_ty]>; -// CHECK: /* 0 */ 21, 14, 15, 0, 57, 0 +// CHECK: /* 0 */ 21, 14, 15, 0, 2, 0 diff --git a/llvm/test/TableGen/intrinsic-varargs.td b/llvm/test/TableGen/intrinsic-varargs.td --- a/llvm/test/TableGen/intrinsic-varargs.td +++ b/llvm/test/TableGen/intrinsic-varargs.td @@ -1,29 +1,7 @@ -// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS | FileCheck %s // XFAIL: vg_leak -include "llvm/CodeGen/ValueTypes.td" - -class IntrinsicProperty { - bit IsDefault = is_default; -} -class SDNodeProperty; - -class LLVMType { - ValueType VT = vt; -} - -class Intrinsic param_types = []> { - string LLVMName = name; - bit isTarget = 0; - string TargetPrefix = ""; - list RetTypes = []; - list ParamTypes = param_types; - list IntrProperties = []; - list Properties = []; - bit DisableDefaultAttributes = 1; -} - -def llvm_vararg_ty : LLVMType; // this means vararg here +include "llvm/IR/Intrinsics.td" // CHECK: /* 0 */ 0, 29, 0, -def int_foo : Intrinsic<"llvm.foo", [llvm_vararg_ty]>; +def int_foo : Intrinsic<[], [llvm_vararg_ty]>; diff --git a/llvm/test/TableGen/range-op-fail.td b/llvm/test/TableGen/range-op-fail.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/range-op-fail.td @@ -0,0 +1,27 @@ +// Each RUN line is scattered. + +defvar list_int = !range(4); + +#ifdef ERR0 +// RUN: not llvm-tblgen %s -DERR0 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR0 +// ERR0: [[FILE]]:[[@LINE+1]]:32: error: expected one list, got extra value of type 'int' +defvar errs = !range(list_int, 42); +#endif + +#ifdef ERR1 +// RUN: not llvm-tblgen %s -DERR1 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR1 +// ERR1: [[FILE]]:[[@LINE+1]]:25: error: expected value of type 'int', got 'list' +defvar errs = !range(0, list_int); +#endif + +#ifdef ERR2 +// RUN: not llvm-tblgen %s -DERR2 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR2 +// ERR2: [[FILE]]:[[@LINE+1]]:15: error: expected at most two values of integer +defvar errs = !range(0, 42, 255); +#endif + +#ifdef ERR3 +// RUN: not llvm-tblgen %s -DERR3 2>&1 | FileCheck -DFILE=%s %s --check-prefix=ERR3 +// ERR3: [[FILE]]:[[@LINE+1]]:22: error: expected list or int, got value of type 'string' +defvar errs = !range("hoge", "fuga"); +#endif diff --git a/llvm/test/TableGen/range-op.td b/llvm/test/TableGen/range-op.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/range-op.td @@ -0,0 +1,16 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +defvar idxs = !range(8); + +// CHECK: def range_op_ranges { +def range_op_ranges { + // CHECK: list> r0 = {{\[}}[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6]]; + list> r0 = !foreach(i, idxs, !range(i)); + + // CHECK: list> rr = {{\[}}[0, 1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5], [2, 3, 4], [3], [], [], [], []]; + list> rr = !foreach(i, idxs, !range(i, !sub(7, i))); + + // CHECK: list i100 = [100, 101, 102, 103, 104, 105, 106, 107]; + list i100 = !foreach(i, !range(rr), !add(100, i)); +} diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -15,6 +15,7 @@ CodeGenHwModes.cpp CodeGenInstAlias.cpp CodeGenInstruction.cpp + CodeGenIntrinsics.cpp CodeGenMapTable.cpp CodeGenRegisters.cpp CodeGenSchedule.cpp diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -1876,7 +1876,7 @@ return 0; // All return nothing. if (Operator->isSubClassOf("Intrinsic")) - return CDP.getIntrinsic(Operator).IS.RetVTs.size(); + return CDP.getIntrinsic(Operator).IS.RetTys.size(); if (Operator->isSubClassOf("SDNode")) return CDP.getSDNodeInfo(Operator).getNumResults(); @@ -2523,11 +2523,12 @@ bool MadeChange = false; // Apply the result type to the node. - unsigned NumRetVTs = Int->IS.RetVTs.size(); - unsigned NumParamVTs = Int->IS.ParamVTs.size(); + unsigned NumRetVTs = Int->IS.RetTys.size(); + unsigned NumParamVTs = Int->IS.ParamTys.size(); for (unsigned i = 0, e = NumRetVTs; i != e; ++i) - MadeChange |= UpdateNodeType(i, Int->IS.RetVTs[i], TP); + MadeChange |= UpdateNodeType( + i, getValueType(Int->IS.RetTys[i]->getValueAsDef("VT")), TP); if (getNumChildren() != NumParamVTs + 1) { TP.error("Intrinsic '" + Int->Name + "' expects " + Twine(NumParamVTs) + @@ -2541,9 +2542,10 @@ for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i) { MadeChange |= getChild(i+1)->ApplyTypeConstraints(TP, NotRegisters); - MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i]; - assert(getChild(i+1)->getNumTypes() == 1 && "Unhandled case"); - MadeChange |= getChild(i+1)->UpdateNodeType(0, OpVT, TP); + MVT::SimpleValueType OpVT = + getValueType(Int->IS.ParamTys[i]->getValueAsDef("VT")); + assert(getChild(i + 1)->getNumTypes() == 1 && "Unhandled case"); + MadeChange |= getChild(i + 1)->UpdateNodeType(0, OpVT, TP); } return MadeChange; } @@ -2995,7 +2997,7 @@ // If this intrinsic returns void, it must have side-effects and thus a // chain. - if (Int.IS.RetVTs.empty()) + if (Int.IS.RetTys.empty()) Operator = getDAGPatterns().get_intrinsic_void_sdnode(); else if (!Int.ME.doesNotAccessMemory() || Int.hasSideEffects) // Has side-effects, requires chain. diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.h b/llvm/utils/TableGen/CodeGenIntrinsics.h --- a/llvm/utils/TableGen/CodeGenIntrinsics.h +++ b/llvm/utils/TableGen/CodeGenIntrinsics.h @@ -15,7 +15,6 @@ #include "SDNodeProperties.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/MachineValueType.h" #include "llvm/Support/ModRef.h" #include #include @@ -43,19 +42,13 @@ /// only populated when in the context of a target .td file. When building /// Intrinsics.td, this isn't available, because we don't know the target /// pointer size. - std::vector RetVTs; - - /// The records for each return type. - std::vector RetTypeDefs; + std::vector RetTys; /// The MVT::SimpleValueType for each parameter type. Note that this list is /// only populated when in the context of a target .td file. When building /// Intrinsics.td, this isn't available, because we don't know the target /// pointer size. - std::vector ParamVTs; - - /// The records for each parameter type. - std::vector ParamTypeDefs; + std::vector ParamTys; }; IntrinsicSignature IS; diff --git a/llvm/utils/TableGen/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/CodeGenIntrinsics.cpp new file mode 100644 --- /dev/null +++ b/llvm/utils/TableGen/CodeGenIntrinsics.cpp @@ -0,0 +1,263 @@ +//===- CodeGenIntrinsics.cpp - Intrinsic Class Wrapper --------------------===// +// +// 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 a wrapper class for the 'Intrinsic' TableGen class. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenIntrinsics.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include +#include +using namespace llvm; + +//===----------------------------------------------------------------------===// +// CodeGenIntrinsic Implementation +//===----------------------------------------------------------------------===// + +CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) { + std::vector IntrProperties = + RC.getAllDerivedDefinitions("IntrinsicProperty"); + + std::vector DefaultProperties; + for (Record *Rec : IntrProperties) + if (Rec->getValueAsBit("IsDefault")) + DefaultProperties.push_back(Rec); + + std::vector Defs = RC.getAllDerivedDefinitions("Intrinsic"); + Intrinsics.reserve(Defs.size()); + + for (unsigned I = 0, e = Defs.size(); I != e; ++I) + Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties)); + + llvm::sort(Intrinsics, + [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) { + return std::tie(LHS.TargetPrefix, LHS.Name) < + std::tie(RHS.TargetPrefix, RHS.Name); + }); + Targets.push_back({"", 0, 0}); + for (size_t I = 0, E = Intrinsics.size(); I < E; ++I) + if (Intrinsics[I].TargetPrefix != Targets.back().Name) { + Targets.back().Count = I - Targets.back().Offset; + Targets.push_back({Intrinsics[I].TargetPrefix, I, 0}); + } + Targets.back().Count = Intrinsics.size() - Targets.back().Offset; +} + +CodeGenIntrinsic::CodeGenIntrinsic(Record *R, + std::vector DefaultProperties) { + TheDef = R; + std::string DefName = std::string(R->getName()); + ArrayRef DefLoc = R->getLoc(); + Properties = 0; + isOverloaded = false; + isCommutative = false; + canThrow = false; + isNoReturn = false; + isNoCallback = false; + isNoSync = false; + isNoFree = false; + isWillReturn = false; + isCold = false; + isNoDuplicate = false; + isNoMerge = false; + isConvergent = false; + isSpeculatable = false; + hasSideEffects = false; + + if (DefName.size() <= 4 || DefName.substr(0, 4) != "int_") + PrintFatalError(DefLoc, + "Intrinsic '" + DefName + "' does not start with 'int_'!"); + + EnumName = DefName.substr(4); + + if (R->getValue( + "ClangBuiltinName")) // Ignore a missing ClangBuiltinName field. + ClangBuiltinName = std::string(R->getValueAsString("ClangBuiltinName")); + if (R->getValue("MSBuiltinName")) // Ignore a missing MSBuiltinName field. + MSBuiltinName = std::string(R->getValueAsString("MSBuiltinName")); + + TargetPrefix = std::string(R->getValueAsString("TargetPrefix")); + Name = std::string(R->getValueAsString("LLVMName")); + + if (Name == "") { + // If an explicit name isn't specified, derive one from the DefName. + Name = "llvm."; + + for (unsigned i = 0, e = EnumName.size(); i != e; ++i) + Name += (EnumName[i] == '_') ? '.' : EnumName[i]; + } else { + // Verify it starts with "llvm.". + if (Name.size() <= 5 || Name.substr(0, 5) != "llvm.") + PrintFatalError(DefLoc, "Intrinsic '" + DefName + + "'s name does not start with 'llvm.'!"); + } + + // If TargetPrefix is specified, make sure that Name starts with + // "llvm..". + if (!TargetPrefix.empty()) { + if (Name.size() < 6 + TargetPrefix.size() || + Name.substr(5, 1 + TargetPrefix.size()) != (TargetPrefix + ".")) + PrintFatalError(DefLoc, "Intrinsic '" + DefName + + "' does not start with 'llvm." + + TargetPrefix + ".'!"); + } + + if (auto *Types = R->getValue("Types")) { + auto *TypeList = dyn_cast(Types->getValue()); + isOverloaded = R->getValueAsBit("isOverloaded"); + + unsigned I = 0; + for (unsigned E = R->getValueAsListInit("RetTypes")->size(); I < E; ++I) + IS.RetTys.push_back(TypeList->getElementAsRecord(I)); + + for (unsigned E = TypeList->size(); I < E; ++I) + IS.ParamTys.push_back(TypeList->getElementAsRecord(I)); + } + + // Parse the intrinsic properties. + ListInit *PropList = R->getValueAsListInit("IntrProperties"); + for (unsigned i = 0, e = PropList->size(); i != e; ++i) { + Record *Property = PropList->getElementAsRecord(i); + assert(Property->isSubClassOf("IntrinsicProperty") && + "Expected a property!"); + + setProperty(Property); + } + + // Set default properties to true. + setDefaultProperties(R, DefaultProperties); + + // Also record the SDPatternOperator Properties. + Properties = parseSDPatternOperatorProperties(R); + + // Sort the argument attributes for later benefit. + for (auto &Attrs : ArgumentAttributes) + llvm::sort(Attrs); +} + +void CodeGenIntrinsic::setDefaultProperties( + Record *R, std::vector DefaultProperties) { + // opt-out of using default attributes. + if (R->getValueAsBit("DisableDefaultAttributes")) + return; + + for (Record *Rec : DefaultProperties) + setProperty(Rec); +} + +void CodeGenIntrinsic::setProperty(Record *R) { + if (R->getName() == "IntrNoMem") + ME = MemoryEffects::none(); + else if (R->getName() == "IntrReadMem") { + if (ME.onlyWritesMemory()) + PrintFatalError(TheDef->getLoc(), + Twine("IntrReadMem cannot be used after IntrNoMem or " + "IntrWriteMem. Default is ReadWrite")); + ME &= MemoryEffects::readOnly(); + } else if (R->getName() == "IntrWriteMem") { + if (ME.onlyReadsMemory()) + PrintFatalError(TheDef->getLoc(), + Twine("IntrWriteMem cannot be used after IntrNoMem or " + "IntrReadMem. Default is ReadWrite")); + ME &= MemoryEffects::writeOnly(); + } else if (R->getName() == "IntrArgMemOnly") + ME &= MemoryEffects::argMemOnly(); + else if (R->getName() == "IntrInaccessibleMemOnly") + ME &= MemoryEffects::inaccessibleMemOnly(); + else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") + ME &= MemoryEffects::inaccessibleOrArgMemOnly(); + else if (R->getName() == "Commutative") + isCommutative = true; + else if (R->getName() == "Throws") + canThrow = true; + else if (R->getName() == "IntrNoDuplicate") + isNoDuplicate = true; + else if (R->getName() == "IntrNoMerge") + isNoMerge = true; + else if (R->getName() == "IntrConvergent") + isConvergent = true; + else if (R->getName() == "IntrNoReturn") + isNoReturn = true; + else if (R->getName() == "IntrNoCallback") + isNoCallback = true; + else if (R->getName() == "IntrNoSync") + isNoSync = true; + else if (R->getName() == "IntrNoFree") + isNoFree = true; + else if (R->getName() == "IntrWillReturn") + isWillReturn = !isNoReturn; + else if (R->getName() == "IntrCold") + isCold = true; + else if (R->getName() == "IntrSpeculatable") + isSpeculatable = true; + else if (R->getName() == "IntrHasSideEffects") + hasSideEffects = true; + else if (R->isSubClassOf("NoCapture")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, NoCapture); + } else if (R->isSubClassOf("NoAlias")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, NoAlias); + } else if (R->isSubClassOf("NoUndef")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, NoUndef); + } else if (R->isSubClassOf("NonNull")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, NonNull); + } else if (R->isSubClassOf("Returned")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, Returned); + } else if (R->isSubClassOf("ReadOnly")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, ReadOnly); + } else if (R->isSubClassOf("WriteOnly")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, WriteOnly); + } else if (R->isSubClassOf("ReadNone")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, ReadNone); + } else if (R->isSubClassOf("ImmArg")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + addArgAttribute(ArgNo, ImmArg); + } else if (R->isSubClassOf("Align")) { + unsigned ArgNo = R->getValueAsInt("ArgNo"); + uint64_t Align = R->getValueAsInt("Align"); + addArgAttribute(ArgNo, Alignment, Align); + } else + llvm_unreachable("Unknown property!"); +} + +bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { + if (ParamIdx >= IS.ParamTys.size()) + return false; + return (IS.ParamTys[ParamIdx]->isSubClassOf("LLVMQualPointerType") || + IS.ParamTys[ParamIdx]->isSubClassOf("LLVMAnyPointerType")); +} + +bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const { + // Convert argument index to attribute index starting from `FirstArgIndex`. + ++ParamIdx; + if (ParamIdx >= ArgumentAttributes.size()) + return false; + ArgAttribute Val{ImmArg, 0}; + return std::binary_search(ArgumentAttributes[ParamIdx].begin(), + ArgumentAttributes[ParamIdx].end(), Val); +} + +void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK, + uint64_t V) { + if (Idx >= ArgumentAttributes.size()) + ArgumentAttributes.resize(Idx + 1); + ArgumentAttributes[Idx].emplace_back(AK, V); +} diff --git a/llvm/utils/TableGen/CodeGenRegisters.cpp b/llvm/utils/TableGen/CodeGenRegisters.cpp --- a/llvm/utils/TableGen/CodeGenRegisters.cpp +++ b/llvm/utils/TableGen/CodeGenRegisters.cpp @@ -1174,8 +1174,8 @@ getReg(Regs[i]); // Expand tuples and number the new registers. - std::vector Tups = - Records.getAllDerivedDefinitions("RegisterTuples"); + std::vector Tups = + Records.getAllDerivedDefinitions("RegisterTuples", false); for (Record *R : Tups) { std::vector TupRegs = *Sets.expand(R); diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -15,13 +15,11 @@ #include "CodeGenTarget.h" #include "CodeGenInstruction.h" -#include "CodeGenIntrinsics.h" #include "CodeGenSchedule.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ModRef.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include @@ -641,319 +639,3 @@ "'!"); } } - -//===----------------------------------------------------------------------===// -// CodeGenIntrinsic Implementation -//===----------------------------------------------------------------------===// - -CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC) { - std::vector IntrProperties = - RC.getAllDerivedDefinitions("IntrinsicProperty"); - - std::vector DefaultProperties; - for (Record *Rec : IntrProperties) - if (Rec->getValueAsBit("IsDefault")) - DefaultProperties.push_back(Rec); - - std::vector Defs = RC.getAllDerivedDefinitions("Intrinsic"); - Intrinsics.reserve(Defs.size()); - - for (unsigned I = 0, e = Defs.size(); I != e; ++I) - Intrinsics.push_back(CodeGenIntrinsic(Defs[I], DefaultProperties)); - - llvm::sort(Intrinsics, - [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) { - return std::tie(LHS.TargetPrefix, LHS.Name) < - std::tie(RHS.TargetPrefix, RHS.Name); - }); - Targets.push_back({"", 0, 0}); - for (size_t I = 0, E = Intrinsics.size(); I < E; ++I) - if (Intrinsics[I].TargetPrefix != Targets.back().Name) { - Targets.back().Count = I - Targets.back().Offset; - Targets.push_back({Intrinsics[I].TargetPrefix, I, 0}); - } - Targets.back().Count = Intrinsics.size() - Targets.back().Offset; -} - -CodeGenIntrinsic::CodeGenIntrinsic(Record *R, - std::vector DefaultProperties) { - TheDef = R; - std::string DefName = std::string(R->getName()); - ArrayRef DefLoc = R->getLoc(); - Properties = 0; - isOverloaded = false; - isCommutative = false; - canThrow = false; - isNoReturn = false; - isNoCallback = false; - isNoSync = false; - isNoFree = false; - isWillReturn = false; - isCold = false; - isNoDuplicate = false; - isNoMerge = false; - isConvergent = false; - isSpeculatable = false; - hasSideEffects = false; - - if (DefName.size() <= 4 || DefName.substr(0, 4) != "int_") - PrintFatalError(DefLoc, - "Intrinsic '" + DefName + "' does not start with 'int_'!"); - - EnumName = DefName.substr(4); - - if (R->getValue( - "ClangBuiltinName")) // Ignore a missing ClangBuiltinName field. - ClangBuiltinName = std::string(R->getValueAsString("ClangBuiltinName")); - if (R->getValue("MSBuiltinName")) // Ignore a missing MSBuiltinName field. - MSBuiltinName = std::string(R->getValueAsString("MSBuiltinName")); - - TargetPrefix = std::string(R->getValueAsString("TargetPrefix")); - Name = std::string(R->getValueAsString("LLVMName")); - - if (Name == "") { - // If an explicit name isn't specified, derive one from the DefName. - Name = "llvm."; - - for (unsigned i = 0, e = EnumName.size(); i != e; ++i) - Name += (EnumName[i] == '_') ? '.' : EnumName[i]; - } else { - // Verify it starts with "llvm.". - if (Name.size() <= 5 || Name.substr(0, 5) != "llvm.") - PrintFatalError(DefLoc, "Intrinsic '" + DefName + - "'s name does not start with 'llvm.'!"); - } - - // If TargetPrefix is specified, make sure that Name starts with - // "llvm..". - if (!TargetPrefix.empty()) { - if (Name.size() < 6 + TargetPrefix.size() || - Name.substr(5, 1 + TargetPrefix.size()) != (TargetPrefix + ".")) - PrintFatalError(DefLoc, "Intrinsic '" + DefName + - "' does not start with 'llvm." + - TargetPrefix + ".'!"); - } - - ListInit *RetTypes = R->getValueAsListInit("RetTypes"); - ListInit *ParamTypes = R->getValueAsListInit("ParamTypes"); - - // First collate a list of overloaded types. - std::vector OverloadedVTs; - for (ListInit *TypeList : {RetTypes, ParamTypes}) { - for (unsigned i = 0, e = TypeList->size(); i != e; ++i) { - Record *TyEl = TypeList->getElementAsRecord(i); - assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!"); - - if (TyEl->isSubClassOf("LLVMMatchType")) - continue; - - MVT::SimpleValueType VT = getValueType(TyEl->getValueAsDef("VT")); - if (MVT(VT).isOverloaded()) { - OverloadedVTs.push_back(VT); - isOverloaded = true; - } - } - } - - // Parse the list of return types. - ListInit *TypeList = RetTypes; - for (unsigned i = 0, e = TypeList->size(); i != e; ++i) { - Record *TyEl = TypeList->getElementAsRecord(i); - assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!"); - MVT::SimpleValueType VT; - if (TyEl->isSubClassOf("LLVMMatchType")) { - unsigned MatchTy = TyEl->getValueAsInt("Number"); - assert(MatchTy < OverloadedVTs.size() && "Invalid matching number!"); - VT = OverloadedVTs[MatchTy]; - // It only makes sense to use the extended and truncated vector element - // variants with iAny types; otherwise, if the intrinsic is not - // overloaded, all the types can be specified directly. - assert(((!TyEl->isSubClassOf("LLVMExtendedType") && - !TyEl->isSubClassOf("LLVMTruncatedType")) || - VT == MVT::iAny || VT == MVT::vAny) && - "Expected iAny or vAny type"); - } else { - VT = getValueType(TyEl->getValueAsDef("VT")); - } - - // Reject invalid types. - if (VT == MVT::isVoid) - PrintFatalError(DefLoc, "Intrinsic '" + DefName + - " has void in result type list!"); - - IS.RetVTs.push_back(VT); - IS.RetTypeDefs.push_back(TyEl); - } - - // Parse the list of parameter types. - TypeList = ParamTypes; - for (unsigned i = 0, e = TypeList->size(); i != e; ++i) { - Record *TyEl = TypeList->getElementAsRecord(i); - assert(TyEl->isSubClassOf("LLVMType") && "Expected a type!"); - MVT::SimpleValueType VT; - if (TyEl->isSubClassOf("LLVMMatchType")) { - unsigned MatchTy = TyEl->getValueAsInt("Number"); - if (MatchTy >= OverloadedVTs.size()) { - PrintError(R->getLoc(), "Parameter #" + Twine(i) + - " has out of bounds matching " - "number " + - Twine(MatchTy)); - PrintFatalError(DefLoc, - Twine("ParamTypes is ") + TypeList->getAsString()); - } - VT = OverloadedVTs[MatchTy]; - // It only makes sense to use the extended and truncated vector element - // variants with iAny types; otherwise, if the intrinsic is not - // overloaded, all the types can be specified directly. - assert(((!TyEl->isSubClassOf("LLVMExtendedType") && - !TyEl->isSubClassOf("LLVMTruncatedType")) || - VT == MVT::iAny || VT == MVT::vAny) && - "Expected iAny or vAny type"); - } else - VT = getValueType(TyEl->getValueAsDef("VT")); - - // Reject invalid types. - if (VT == MVT::isVoid && i != e - 1 /*void at end means varargs*/) - PrintFatalError(DefLoc, "Intrinsic '" + DefName + - " has void in result type list!"); - - IS.ParamVTs.push_back(VT); - IS.ParamTypeDefs.push_back(TyEl); - } - - // Parse the intrinsic properties. - ListInit *PropList = R->getValueAsListInit("IntrProperties"); - for (unsigned i = 0, e = PropList->size(); i != e; ++i) { - Record *Property = PropList->getElementAsRecord(i); - assert(Property->isSubClassOf("IntrinsicProperty") && - "Expected a property!"); - - setProperty(Property); - } - - // Set default properties to true. - setDefaultProperties(R, DefaultProperties); - - // Also record the SDPatternOperator Properties. - Properties = parseSDPatternOperatorProperties(R); - - // Sort the argument attributes for later benefit. - for (auto &Attrs : ArgumentAttributes) - llvm::sort(Attrs); -} - -void CodeGenIntrinsic::setDefaultProperties( - Record *R, std::vector DefaultProperties) { - // opt-out of using default attributes. - if (R->getValueAsBit("DisableDefaultAttributes")) - return; - - for (Record *Rec : DefaultProperties) - setProperty(Rec); -} - -void CodeGenIntrinsic::setProperty(Record *R) { - if (R->getName() == "IntrNoMem") - ME = MemoryEffects::none(); - else if (R->getName() == "IntrReadMem") { - if (ME.onlyWritesMemory()) - PrintFatalError(TheDef->getLoc(), - Twine("IntrReadMem cannot be used after IntrNoMem or " - "IntrWriteMem. Default is ReadWrite")); - ME &= MemoryEffects::readOnly(); - } else if (R->getName() == "IntrWriteMem") { - if (ME.onlyReadsMemory()) - PrintFatalError(TheDef->getLoc(), - Twine("IntrWriteMem cannot be used after IntrNoMem or " - "IntrReadMem. Default is ReadWrite")); - ME &= MemoryEffects::writeOnly(); - } else if (R->getName() == "IntrArgMemOnly") - ME &= MemoryEffects::argMemOnly(); - else if (R->getName() == "IntrInaccessibleMemOnly") - ME &= MemoryEffects::inaccessibleMemOnly(); - else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly") - ME &= MemoryEffects::inaccessibleOrArgMemOnly(); - else if (R->getName() == "Commutative") - isCommutative = true; - else if (R->getName() == "Throws") - canThrow = true; - else if (R->getName() == "IntrNoDuplicate") - isNoDuplicate = true; - else if (R->getName() == "IntrNoMerge") - isNoMerge = true; - else if (R->getName() == "IntrConvergent") - isConvergent = true; - else if (R->getName() == "IntrNoReturn") - isNoReturn = true; - else if (R->getName() == "IntrNoCallback") - isNoCallback = true; - else if (R->getName() == "IntrNoSync") - isNoSync = true; - else if (R->getName() == "IntrNoFree") - isNoFree = true; - else if (R->getName() == "IntrWillReturn") - isWillReturn = !isNoReturn; - else if (R->getName() == "IntrCold") - isCold = true; - else if (R->getName() == "IntrSpeculatable") - isSpeculatable = true; - else if (R->getName() == "IntrHasSideEffects") - hasSideEffects = true; - else if (R->isSubClassOf("NoCapture")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, NoCapture); - } else if (R->isSubClassOf("NoAlias")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, NoAlias); - } else if (R->isSubClassOf("NoUndef")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, NoUndef); - } else if (R->isSubClassOf("NonNull")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, NonNull); - } else if (R->isSubClassOf("Returned")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, Returned); - } else if (R->isSubClassOf("ReadOnly")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, ReadOnly); - } else if (R->isSubClassOf("WriteOnly")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, WriteOnly); - } else if (R->isSubClassOf("ReadNone")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, ReadNone); - } else if (R->isSubClassOf("ImmArg")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - addArgAttribute(ArgNo, ImmArg); - } else if (R->isSubClassOf("Align")) { - unsigned ArgNo = R->getValueAsInt("ArgNo"); - uint64_t Align = R->getValueAsInt("Align"); - addArgAttribute(ArgNo, Alignment, Align); - } else - llvm_unreachable("Unknown property!"); -} - -bool CodeGenIntrinsic::isParamAPointer(unsigned ParamIdx) const { - if (ParamIdx >= IS.ParamVTs.size()) - return false; - MVT ParamType = MVT(IS.ParamVTs[ParamIdx]); - return ParamType == MVT::iPTR || ParamType == MVT::iPTRAny; -} - -bool CodeGenIntrinsic::isParamImmArg(unsigned ParamIdx) const { - // Convert argument index to attribute index starting from `FirstArgIndex`. - ++ParamIdx; - if (ParamIdx >= ArgumentAttributes.size()) - return false; - ArgAttribute Val{ImmArg, 0}; - return std::binary_search(ArgumentAttributes[ParamIdx].begin(), - ArgumentAttributes[ParamIdx].end(), Val); -} - -void CodeGenIntrinsic::addArgAttribute(unsigned Idx, ArgAttrKind AK, - uint64_t V) { - if (Idx >= ArgumentAttributes.size()) - ArgumentAttributes.resize(Idx + 1); - ArgumentAttributes[Idx].emplace_back(AK, V); -} diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "CodeGenIntrinsics.h" -#include "CodeGenTarget.h" #include "SequenceToOffsetTable.h" #include "TableGenBackends.h" #include "llvm/ADT/ArrayRef.h" @@ -22,7 +21,6 @@ #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MachineValueType.h" #include "llvm/Support/ModRef.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" @@ -54,6 +52,8 @@ void run(raw_ostream &OS, bool Enums); void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); + void EmitArgKind(raw_ostream &OS); + void EmitIITInfo(raw_ostream &OS); void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints, raw_ostream &OS); @@ -78,7 +78,13 @@ if (Enums) { // Emit the enum information. EmitEnumInfo(Ints, OS); + + // Emit ArgKind for Intrinsics.h. + EmitArgKind(OS); } else { + // Emit IIT_Info constants. + EmitIITInfo(OS); + // Emit the target metadata. EmitTargetInfo(Ints, OS); @@ -125,7 +131,9 @@ } // Generate a complete header for target specific intrinsics. - if (!IntrinsicPrefix.empty()) { + if (IntrinsicPrefix.empty()) { + OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n"; + } else { std::string UpperPrefix = StringRef(IntrinsicPrefix).upper(); OS << "#ifndef LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n"; OS << "#define LLVM_IR_INTRINSIC_" << UpperPrefix << "_ENUMS_H\n\n"; @@ -152,6 +160,7 @@ // Emit num_intrinsics into the target neutral enum. if (IntrinsicPrefix.empty()) { OS << " num_intrinsics = " << (Ints.size() + 1) << "\n"; + OS << "#endif\n\n"; } else { OS << "}; // enum\n"; OS << "} // namespace Intrinsic\n"; @@ -160,6 +169,40 @@ } } +void IntrinsicEmitter::EmitArgKind(raw_ostream &OS) { + if (!IntrinsicPrefix.empty()) + return; + OS << "// llvm::Intrinsic::IITDescriptor::ArgKind\n"; + OS << "#ifdef GET_INTRINSIC_ARGKIND\n"; + if (auto RecArgKind = Records.getDef("ArgKind")) { + for (auto &Rec : RecArgKind->getValues()) + OS << " AK_" << Rec.getName() << " = " << *Rec.getValue() << ",\n"; + } else { + OS << "#error \"ArgKind is not defined\"\n"; + } + OS << "#endif\n\n"; +} + +void IntrinsicEmitter::EmitIITInfo(raw_ostream &OS) { + OS << "#ifdef GET_INTRINSIC_IITINFO\n"; + std::vector RecsByNumber(256); + auto IIT_Base = Records.getAllDerivedDefinitionsIfDefined("IIT_Base"); + for (auto Rec : IIT_Base) { + auto Number = Rec->getValueAsInt("Number"); + assert(0 <= Number && Number < 256 && "IIT_Info.Number should be uint8_t"); + assert(RecsByNumber[Number].empty() && "Duplicate IIT_Info.Number"); + RecsByNumber[Number] = Rec->getName(); + } + if (IIT_Base.size() > 0) { + for (unsigned I = 0, E = RecsByNumber.size(); I < E; ++I) + if (!RecsByNumber[I].empty()) + OS << " " << RecsByNumber[I] << " = " << I << ",\n"; + } else { + OS << "#error \"class IIT_Base is not defined\"\n"; + } + OS << "#endif\n\n"; +} + void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS) { OS << "// Target mapping\n"; @@ -206,327 +249,16 @@ OS << "#endif\n\n"; } - -// NOTE: This must be kept in synch with the copy in lib/IR/Function.cpp! -enum IIT_Info { - // Common values should be encoded with 0-15. - IIT_Done = 0, - IIT_I1 = 1, - IIT_I8 = 2, - IIT_I16 = 3, - IIT_I32 = 4, - IIT_I64 = 5, - IIT_F16 = 6, - IIT_F32 = 7, - IIT_F64 = 8, - IIT_V2 = 9, - IIT_V4 = 10, - IIT_V8 = 11, - IIT_V16 = 12, - IIT_V32 = 13, - IIT_PTR = 14, - IIT_ARG = 15, - - // Values from 16+ are only encodable with the inefficient encoding. - IIT_V64 = 16, - IIT_MMX = 17, - IIT_TOKEN = 18, - IIT_METADATA = 19, - IIT_EMPTYSTRUCT = 20, - IIT_STRUCT2 = 21, - IIT_STRUCT3 = 22, - IIT_STRUCT4 = 23, - IIT_STRUCT5 = 24, - IIT_EXTEND_ARG = 25, - IIT_TRUNC_ARG = 26, - IIT_ANYPTR = 27, - IIT_V1 = 28, - IIT_VARARG = 29, - IIT_HALF_VEC_ARG = 30, - IIT_SAME_VEC_WIDTH_ARG = 31, - IIT_PTR_TO_ARG = 32, - IIT_PTR_TO_ELT = 33, - IIT_VEC_OF_ANYPTRS_TO_ELT = 34, - IIT_I128 = 35, - IIT_V512 = 36, - IIT_V1024 = 37, - IIT_STRUCT6 = 38, - IIT_STRUCT7 = 39, - IIT_STRUCT8 = 40, - IIT_F128 = 41, - IIT_VEC_ELEMENT = 42, - IIT_SCALABLE_VEC = 43, - IIT_SUBDIVIDE2_ARG = 44, - IIT_SUBDIVIDE4_ARG = 45, - IIT_VEC_OF_BITCASTS_TO_INT = 46, - IIT_V128 = 47, - IIT_BF16 = 48, - IIT_STRUCT9 = 49, - IIT_V256 = 50, - IIT_AMX = 51, - IIT_PPCF128 = 52, - IIT_V3 = 53, - IIT_EXTERNREF = 54, - IIT_FUNCREF = 55, - IIT_ANYPTR_TO_ELT = 56, - IIT_I2 = 57, - IIT_I4 = 58, -}; - -static void EncodeFixedValueType(MVT::SimpleValueType VT, - std::vector &Sig) { - // clang-format off - if (MVT(VT).isInteger()) { - unsigned BitWidth = MVT(VT).getFixedSizeInBits(); - switch (BitWidth) { - default: PrintFatalError("unhandled integer type width in intrinsic!"); - case 1: return Sig.push_back(IIT_I1); - case 2: return Sig.push_back(IIT_I2); - case 4: return Sig.push_back(IIT_I4); - case 8: return Sig.push_back(IIT_I8); - case 16: return Sig.push_back(IIT_I16); - case 32: return Sig.push_back(IIT_I32); - case 64: return Sig.push_back(IIT_I64); - case 128: return Sig.push_back(IIT_I128); - } - } - - switch (VT) { - default: PrintFatalError("unhandled MVT in intrinsic!"); - case MVT::f16: return Sig.push_back(IIT_F16); - case MVT::bf16: return Sig.push_back(IIT_BF16); - case MVT::f32: return Sig.push_back(IIT_F32); - case MVT::f64: return Sig.push_back(IIT_F64); - case MVT::f128: return Sig.push_back(IIT_F128); - case MVT::ppcf128: return Sig.push_back(IIT_PPCF128); - case MVT::token: return Sig.push_back(IIT_TOKEN); - case MVT::Metadata: return Sig.push_back(IIT_METADATA); - case MVT::x86mmx: return Sig.push_back(IIT_MMX); - case MVT::x86amx: return Sig.push_back(IIT_AMX); - // MVT::OtherVT is used to mean the empty struct type here. - case MVT::Other: return Sig.push_back(IIT_EMPTYSTRUCT); - // MVT::isVoid is used to represent varargs here. - case MVT::isVoid: return Sig.push_back(IIT_VARARG); - case MVT::externref: - return Sig.push_back(IIT_EXTERNREF); - case MVT::funcref: - return Sig.push_back(IIT_FUNCREF); - } - // clang-format on -} - -#if defined(_MSC_VER) && !defined(__clang__) -#pragma optimize("",off) // MSVC 2015 optimizer can't deal with this function. -#endif - -static void EncodeFixedType(Record *R, std::vector &ArgCodes, - unsigned &NextArgCode, - std::vector &Sig, - ArrayRef Mapping) { - - if (R->isSubClassOf("LLVMMatchType")) { - unsigned Number = Mapping[R->getValueAsInt("Number")]; - assert(Number < ArgCodes.size() && "Invalid matching number!"); - if (R->isSubClassOf("LLVMExtendedType")) - Sig.push_back(IIT_EXTEND_ARG); - else if (R->isSubClassOf("LLVMTruncatedType")) - Sig.push_back(IIT_TRUNC_ARG); - else if (R->isSubClassOf("LLVMHalfElementsVectorType")) - Sig.push_back(IIT_HALF_VEC_ARG); - else if (R->isSubClassOf("LLVMScalarOrSameVectorWidth")) { - Sig.push_back(IIT_SAME_VEC_WIDTH_ARG); - Sig.push_back((Number << 3) | ArgCodes[Number]); - MVT::SimpleValueType VT = getValueType(R->getValueAsDef("ElTy")); - EncodeFixedValueType(VT, Sig); - return; - } - else if (R->isSubClassOf("LLVMPointerTo")) - Sig.push_back(IIT_PTR_TO_ARG); - else if (R->isSubClassOf("LLVMVectorOfAnyPointersToElt")) { - Sig.push_back(IIT_VEC_OF_ANYPTRS_TO_ELT); - // Encode overloaded ArgNo - Sig.push_back(NextArgCode++); - // Encode LLVMMatchType ArgNo - Sig.push_back(Number); - return; - } else if (R->isSubClassOf("LLVMAnyPointerToElt")) { - Sig.push_back(IIT_ANYPTR_TO_ELT); - // Encode overloaded ArgNo - Sig.push_back(NextArgCode++); - // Encode LLVMMatchType ArgNo - Sig.push_back(Number); - return; - } else if (R->isSubClassOf("LLVMPointerToElt")) - Sig.push_back(IIT_PTR_TO_ELT); - else if (R->isSubClassOf("LLVMVectorElementType")) - Sig.push_back(IIT_VEC_ELEMENT); - else if (R->isSubClassOf("LLVMSubdivide2VectorType")) - Sig.push_back(IIT_SUBDIVIDE2_ARG); - else if (R->isSubClassOf("LLVMSubdivide4VectorType")) - Sig.push_back(IIT_SUBDIVIDE4_ARG); - else if (R->isSubClassOf("LLVMVectorOfBitcastsToInt")) - Sig.push_back(IIT_VEC_OF_BITCASTS_TO_INT); - else - Sig.push_back(IIT_ARG); - return Sig.push_back((Number << 3) | 7 /*IITDescriptor::AK_MatchType*/); - } - - MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT")); - - unsigned Tmp = 0; - switch (VT) { - default: break; - case MVT::iPTRAny: ++Tmp; [[fallthrough]]; - case MVT::vAny: ++Tmp; [[fallthrough]]; - case MVT::fAny: ++Tmp; [[fallthrough]]; - case MVT::iAny: ++Tmp; [[fallthrough]]; - case MVT::Any: { - // If this is an "any" valuetype, then the type is the type of the next - // type in the list specified to getIntrinsic(). - Sig.push_back(IIT_ARG); - - // Figure out what arg # this is consuming, and remember what kind it was. - assert(NextArgCode < ArgCodes.size() && ArgCodes[NextArgCode] == Tmp && - "Invalid or no ArgCode associated with overloaded VT!"); - unsigned ArgNo = NextArgCode++; - - // Encode what sort of argument it must be in the low 3 bits of the ArgNo. - return Sig.push_back((ArgNo << 3) | Tmp); - } - - case MVT::iPTR: { - unsigned AddrSpace = 0; - if (R->isSubClassOf("LLVMQualPointerType")) { - AddrSpace = R->getValueAsInt("AddrSpace"); - assert(AddrSpace < 256 && "Address space exceeds 255"); - } - if (AddrSpace) { - Sig.push_back(IIT_ANYPTR); - Sig.push_back(AddrSpace); - } else { - Sig.push_back(IIT_PTR); - } - return EncodeFixedType(R->getValueAsDef("ElTy"), ArgCodes, NextArgCode, Sig, - Mapping); - } - } - - if (MVT(VT).isVector()) { - MVT VVT = VT; - if (VVT.isScalableVector()) - Sig.push_back(IIT_SCALABLE_VEC); - switch (VVT.getVectorMinNumElements()) { - default: PrintFatalError("unhandled vector type width in intrinsic!"); - case 1: Sig.push_back(IIT_V1); break; - case 2: Sig.push_back(IIT_V2); break; - case 3: Sig.push_back(IIT_V3); break; - case 4: Sig.push_back(IIT_V4); break; - case 8: Sig.push_back(IIT_V8); break; - case 16: Sig.push_back(IIT_V16); break; - case 32: Sig.push_back(IIT_V32); break; - case 64: Sig.push_back(IIT_V64); break; - case 128: Sig.push_back(IIT_V128); break; - case 256: Sig.push_back(IIT_V256); break; - case 512: Sig.push_back(IIT_V512); break; - case 1024: Sig.push_back(IIT_V1024); break; - } - - return EncodeFixedValueType(VVT.getVectorElementType().SimpleTy, Sig); - } - - EncodeFixedValueType(VT, Sig); -} - -static void UpdateArgCodes(Record *R, std::vector &ArgCodes, - unsigned int &NumInserted, - SmallVectorImpl &Mapping) { - if (R->isSubClassOf("LLVMMatchType")) { - if (R->isSubClassOf("LLVMVectorOfAnyPointersToElt")) { - ArgCodes.push_back(3 /*vAny*/); - ++NumInserted; - } else if (R->isSubClassOf("LLVMAnyPointerToElt")) { - ArgCodes.push_back(4 /*iPTRAny*/); - ++NumInserted; - } - return; - } - - unsigned Tmp = 0; - switch (getValueType(R->getValueAsDef("VT"))) { - default: break; - case MVT::iPTR: - UpdateArgCodes(R->getValueAsDef("ElTy"), ArgCodes, NumInserted, Mapping); - break; - case MVT::iPTRAny: - ++Tmp; - [[fallthrough]]; - case MVT::vAny: - ++Tmp; - [[fallthrough]]; - case MVT::fAny: - ++Tmp; - [[fallthrough]]; - case MVT::iAny: - ++Tmp; - [[fallthrough]]; - case MVT::Any: - unsigned OriginalIdx = ArgCodes.size() - NumInserted; - assert(OriginalIdx >= Mapping.size()); - Mapping.resize(OriginalIdx+1); - Mapping[OriginalIdx] = ArgCodes.size(); - ArgCodes.push_back(Tmp); - break; - } -} - -#if defined(_MSC_VER) && !defined(__clang__) -#pragma optimize("",on) -#endif - /// ComputeFixedEncoding - If we can encode the type signature for this /// intrinsic into 32 bits, return it. If not, return ~0U. static void ComputeFixedEncoding(const CodeGenIntrinsic &Int, std::vector &TypeSig) { - std::vector ArgCodes; - - // Add codes for any overloaded result VTs. - unsigned int NumInserted = 0; - SmallVector ArgMapping; - for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i) - UpdateArgCodes(Int.IS.RetTypeDefs[i], ArgCodes, NumInserted, ArgMapping); - - // Add codes for any overloaded operand VTs. - for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i) - UpdateArgCodes(Int.IS.ParamTypeDefs[i], ArgCodes, NumInserted, ArgMapping); - - unsigned NextArgCode = 0; - if (Int.IS.RetVTs.empty()) - TypeSig.push_back(IIT_Done); - else if (Int.IS.RetVTs.size() == 1 && - Int.IS.RetVTs[0] == MVT::isVoid) - TypeSig.push_back(IIT_Done); - else { - switch (Int.IS.RetVTs.size()) { - case 1: break; - case 2: TypeSig.push_back(IIT_STRUCT2); break; - case 3: TypeSig.push_back(IIT_STRUCT3); break; - case 4: TypeSig.push_back(IIT_STRUCT4); break; - case 5: TypeSig.push_back(IIT_STRUCT5); break; - case 6: TypeSig.push_back(IIT_STRUCT6); break; - case 7: TypeSig.push_back(IIT_STRUCT7); break; - case 8: TypeSig.push_back(IIT_STRUCT8); break; - case 9: TypeSig.push_back(IIT_STRUCT9); break; - default: llvm_unreachable("Unhandled case in struct"); + if (auto *R = Int.TheDef->getValue("TypeSig")) { + for (auto &a : dyn_cast(R->getValue())->getValues()) { + for (auto &b : dyn_cast(a)->getValues()) + TypeSig.push_back(dyn_cast(b)->getValue()); } - - for (unsigned i = 0, e = Int.IS.RetVTs.size(); i != e; ++i) - EncodeFixedType(Int.IS.RetTypeDefs[i], ArgCodes, NextArgCode, TypeSig, - ArgMapping); } - - for (unsigned i = 0, e = Int.IS.ParamTypeDefs.size(); i != e; ++i) - EncodeFixedType(Int.IS.ParamTypeDefs[i], ArgCodes, NextArgCode, TypeSig, - ArgMapping); } static void printIITEntry(raw_ostream &OS, unsigned char X) {