| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | /*****************************************************************************/ |
| 6 | #ifndef SIMD_INTRINSIC |
| 7 | #error Define SIMD_INTRINSIC before including this file |
| 8 | #endif |
| 9 | /*****************************************************************************/ |
| 10 | |
| 11 | // clang-format off |
| 12 | #ifdef FEATURE_SIMD |
| 13 | |
| 14 | /* |
| 15 | Notes: |
| 16 | a) TYP_UNKNOWN means 'baseType' of SIMD vector which is not known apriori |
| 17 | b) Each method maps to a unique intrinsic Id |
| 18 | c) To facilitate argument types to be used as an array initializer, args are listed within "{}" braces. |
| 19 | d) Since comma is used as actual param seperator in a macro, TYP_UNDEF entries are added to keep param count constant. |
| 20 | e) TODO-Cleanup: when we plumb TYP_SIMD through front-end, replace TYP_STRUCT with TYP_SIMD. |
| 21 | */ |
| 22 | |
| 23 | #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_) |
| 24 | |
| 25 | // Max number of parameters that we model in the table for SIMD intrinsic methods. |
| 26 | #define SIMD_INTRINSIC_MAX_MODELED_PARAM_COUNT 3 |
| 27 | |
| 28 | // Actual maximum number of parameters for any SIMD intrinsic method. |
| 29 | // Constructors that take either N values, or a smaller Vector plus additional element values, |
| 30 | // actually have more arguments than the "modeled" count. |
| 31 | #define SIMD_INTRINSIC_MAX_PARAM_COUNT 5 |
| 32 | |
| 33 | // Max number of base types supported by an intrinsic |
| 34 | #define SIMD_INTRINSIC_MAX_BASETYPE_COUNT 10 |
| 35 | |
| 36 | /*************************************************************************************************************************************************************************************************************************** |
| 37 | Method Name, Is Instance Intrinsic Id, Display Name, return type, Arg count, Individual argument types Supported base types |
| 38 | Method (including implicit "this") |
| 39 | ***************************************************************************************************************************************************************************************************************************/ |
| 40 | SIMD_INTRINSIC(nullptr, false, None, "None" , TYP_UNDEF, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 41 | |
| 42 | SIMD_INTRINSIC("get_Count" , false, GetCount, "count" , TYP_INT, 0, {TYP_VOID, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 43 | SIMD_INTRINSIC("get_One" , false, GetOne, "one" , TYP_STRUCT, 0, {TYP_VOID, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 44 | SIMD_INTRINSIC("get_Zero" , false, GetZero, "zero" , TYP_STRUCT, 0, {TYP_VOID, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 45 | SIMD_INTRINSIC("get_AllOnes" , false, GetAllOnes, "allOnes" , TYP_STRUCT, 0, {TYP_VOID, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 46 | |
| 47 | // .ctor call or newobj - there are four forms. |
| 48 | // This form takes the object plus a value of the base (element) type: |
| 49 | SIMD_INTRINSIC(".ctor" , true, Init, "init" , TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 50 | // This form takes the object plus an array of the base (element) type: |
| 51 | SIMD_INTRINSIC(".ctor" , true, InitArray, "initArray" , TYP_VOID, 2, {TYP_BYREF, TYP_REF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 52 | // This form takes the object, an array of the base (element) type, and an index into the array: |
| 53 | SIMD_INTRINSIC(".ctor" , true, InitArrayX, "initArray" , TYP_VOID, 3, {TYP_BYREF, TYP_REF, TYP_INT }, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 54 | // This form takes the object, and N values of the base (element) type. The actual number of arguments depends upon the Vector size, which must be a fixed type such as Vector2f/3f/4f |
| 55 | // Right now this intrinsic is supported only on fixed float vectors and hence the supported base types lists only TYP_FLOAT. |
| 56 | // This is currently the intrinsic that has the largest maximum number of operands - if we add new fixed vector types |
| 57 | // with more than 4 elements, the above SIMD_INTRINSIC_MAX_PARAM_COUNT will have to change. |
| 58 | SIMD_INTRINSIC(".ctor" , true, InitN, "initN" , TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNKNOWN}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 59 | // This form takes the object, a smaller fixed vector, and one or two additional arguments of the base type, e.g. Vector3 V = new Vector3(V2, x); where V2 is a Vector2, and x is a float. |
| 60 | SIMD_INTRINSIC(".ctor" , true, InitFixed, "initFixed" , TYP_VOID, 3, {TYP_BYREF, TYP_STRUCT, TYP_UNKNOWN}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 61 | |
| 62 | // Copy vector to an array |
| 63 | SIMD_INTRINSIC("CopyTo" , true, CopyToArray, "CopyToArray" , TYP_VOID, 2, {TYP_BYREF, TYP_REF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 64 | SIMD_INTRINSIC("CopyTo" , true, CopyToArrayX, "CopyToArray" , TYP_VOID, 3, {TYP_BYREF, TYP_REF, TYP_INT }, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 65 | |
| 66 | // Get operations |
| 67 | SIMD_INTRINSIC("get_Item" , true, GetItem, "get[i]" , TYP_UNKNOWN, 2, {TYP_BYREF, TYP_INT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 68 | SIMD_INTRINSIC("get_X" , true, GetX, "getX" , TYP_UNKNOWN, 1, {TYP_BYREF, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 69 | SIMD_INTRINSIC("get_Y" , true, GetY, "getY" , TYP_UNKNOWN, 1, {TYP_BYREF, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 70 | SIMD_INTRINSIC("get_Z" , true, GetZ, "getZ" , TYP_UNKNOWN, 1, {TYP_BYREF, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 71 | SIMD_INTRINSIC("get_W" , true, GetW, "getW" , TYP_UNKNOWN, 1, {TYP_BYREF, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 72 | |
| 73 | // Set operations |
| 74 | SIMD_INTRINSIC("set_X" , true, SetX, "setX" , TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 75 | SIMD_INTRINSIC("set_Y" , true, SetY, "setY" , TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 76 | SIMD_INTRINSIC("set_Z" , true, SetZ, "setZ" , TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 77 | SIMD_INTRINSIC("set_W" , true, SetW, "setW" , TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 78 | |
| 79 | // Object.Equals() |
| 80 | SIMD_INTRINSIC("Equals" , true, InstEquals, "equals" , TYP_BOOL, 2, {TYP_BYREF, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 81 | |
| 82 | // Operator == and != |
| 83 | SIMD_INTRINSIC("op_Equality" , false, OpEquality, "==" , TYP_BOOL, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 84 | SIMD_INTRINSIC("op_Inequality" , false, OpInEquality, "!=" , TYP_BOOL, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 85 | |
| 86 | // Arithmetic Operations |
| 87 | SIMD_INTRINSIC("op_Addition" , false, Add, "+" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 88 | SIMD_INTRINSIC("op_Subtraction" , false, Sub, "-" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 89 | |
| 90 | #if defined(_TARGET_XARCH_) |
| 91 | SIMD_INTRINSIC("op_Multiply" , false, Mul, "*" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_SHORT,TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 92 | #elif defined(_TARGET_ARM64_) |
| 93 | // TODO-ARM64-CQ Investigate code sequence to accelerate LONG/ULONG vector multiply |
| 94 | SIMD_INTRINSIC("op_Multiply" , false, Mul, "*" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF}) |
| 95 | #endif |
| 96 | |
| 97 | SIMD_INTRINSIC("op_Division" , false, Div, "/" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 98 | |
| 99 | // SquareRoot is recognized as an intrinsic only for float or double vectors |
| 100 | SIMD_INTRINSIC("SquareRoot" , false, Sqrt, "sqrt" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 101 | |
| 102 | SIMD_INTRINSIC("Min" , false, Min, "min" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 103 | SIMD_INTRINSIC("Max" , false, Max, "max" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 104 | SIMD_INTRINSIC("Abs" , false, Abs, "abs" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF }, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 105 | |
| 106 | // Vector Relational operators |
| 107 | SIMD_INTRINSIC("Equals" , false, Equal, "eq" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 108 | SIMD_INTRINSIC("LessThan" , false, LessThan, "lt" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 109 | SIMD_INTRINSIC("LessThanOrEqual" , false, LessThanOrEqual, "le" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 110 | SIMD_INTRINSIC("GreaterThan" , false, GreaterThan, "gt" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 111 | SIMD_INTRINSIC("GreaterThanOrEqual" , false, GreaterThanOrEqual, "ge" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 112 | |
| 113 | // Bitwise operations |
| 114 | SIMD_INTRINSIC("op_BitwiseAnd" , false, BitwiseAnd, "&" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 115 | SIMD_INTRINSIC("AndNot" , false, BitwiseAndNot, "&~" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 116 | SIMD_INTRINSIC("op_BitwiseOr" , false, BitwiseOr, "|" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 117 | SIMD_INTRINSIC("op_ExclusiveOr" , false, BitwiseXor, "^" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 118 | |
| 119 | // Dot Product |
| 120 | #if defined(_TARGET_XARCH_) |
| 121 | // Is supported only on Vector<int> on AVX. |
| 122 | SIMD_INTRINSIC("Dot" , false, DotProduct, "Dot" , TYP_UNKNOWN, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 123 | #elif defined(_TARGET_ARM64_) |
| 124 | // Dot Product does not support LONG/ULONG due to lack of multiply support (see TODO-ARM64-CQ above) |
| 125 | SIMD_INTRINSIC("Dot" , false, DotProduct, "Dot" , TYP_UNKNOWN, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF}) |
| 126 | #endif |
| 127 | |
| 128 | // Select |
| 129 | SIMD_INTRINSIC("ConditionalSelect" , false, Select, "Select" , TYP_STRUCT, 3, {TYP_STRUCT, TYP_STRUCT, TYP_STRUCT}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 130 | |
| 131 | // Cast |
| 132 | SIMD_INTRINSIC("op_Explicit" , false, Cast, "Cast" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) |
| 133 | |
| 134 | // Convert int/uint to single |
| 135 | SIMD_INTRINSIC("ConvertToSingle" , false, ConvertToSingle, "ConvertToSingle" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_UINT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 136 | // Convert long/ulong to double |
| 137 | SIMD_INTRINSIC("ConvertToDouble" , false, ConvertToDouble, "ConvertToDouble" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_LONG, TYP_ULONG, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 138 | // Convert single to int |
| 139 | SIMD_INTRINSIC("ConvertToInt32" , false, ConvertToInt32, "ConvertToInt32" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 140 | // Convert double to long |
| 141 | SIMD_INTRINSIC("ConvertToInt64" , false, ConvertToInt64, "ConvertToInt64" , TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 142 | // Narrow two input Vector<T>s to a single Vector<T>. The return value's lower elements are the elements from src1, and the upper elements are from src2. |
| 143 | SIMD_INTRINSIC("Narrow" , false, Narrow, "Narrow" , TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_SHORT, TYP_UINT, TYP_ULONG, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 144 | // Widen one input Vector<T> to two Vector<T>s: dest1 contains the lower half of elements in src, and dest2 contains the upper half of elements in src. |
| 145 | SIMD_INTRINSIC("Widen" , false, Widen, "Widen" , TYP_VOID, 3, {TYP_STRUCT, TYP_BYREF, TYP_BYREF}, {TYP_INT, TYP_FLOAT, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 146 | |
| 147 | // Miscellaneous |
| 148 | SIMD_INTRINSIC("get_IsHardwareAccelerated" , false, HWAccel, "HWAccel" , TYP_BOOL, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 149 | |
| 150 | #ifdef _TARGET_XARCH_ |
| 151 | // Shuffle and Shift operations - these are internal intrinsics as there is no corresponding managed method. |
| 152 | // To prevent this being accidentally recognized as an intrinsic, all of the arg types and supported base types is made TYP_UNDEF |
| 153 | SIMD_INTRINSIC("ShuffleSSE2" , false, ShuffleSSE2, "ShuffleSSE2" , TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 154 | |
| 155 | // Internal, logical shift operations that shift the entire vector register instead of individual elements of the vector. |
| 156 | SIMD_INTRINSIC("ShiftLeftInternal" , false, ShiftLeftInternal, "<< Internal" , TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 157 | SIMD_INTRINSIC("ShiftRightInternal" , false, ShiftRightInternal, ">> Internal" , TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 158 | #endif // _TARGET_XARCH_ |
| 159 | |
| 160 | // Internal intrinsics for saving & restoring the upper half of a vector register |
| 161 | SIMD_INTRINSIC("UpperSave" , false, UpperSave, "UpperSave Internal" , TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 162 | SIMD_INTRINSIC("UpperRestore" , false, UpperRestore, "UpperRestore Internal" , TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 163 | |
| 164 | // Internal intrinsics for Widen |
| 165 | SIMD_INTRINSIC("WidenHi" , false, WidenHi, "WidenHi" , TYP_VOID, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 166 | SIMD_INTRINSIC("WidenLo" , false, WidenLo, "WidenLo" , TYP_VOID, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 167 | |
| 168 | SIMD_INTRINSIC(nullptr, false, Invalid, "Invalid" , TYP_UNDEF, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) |
| 169 | #undef SIMD_INTRINSIC |
| 170 | #else // !defined(_TARGET_XARCH_) && !defined(_TARGET_ARM64_) |
| 171 | #error SIMD intrinsics not defined for target arch |
| 172 | #endif // !defined(_TARGET_XARCH_) && !defined(_TARGET_ARM64_) |
| 173 | |
| 174 | |
| 175 | #endif //FEATURE_SIMD |
| 176 | // clang-format on |
| 177 | |