summaryrefslogtreecommitdiff
path: root/src/jit/hwintrinsicxarch.h
blob: 4af604e3ccb076d959c64f4d7dd1fb7a0e89ed6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef _HW_INTRINSIC_XARCH_H_
#define _HW_INTRINSIC_XARCH_H_

#ifdef FEATURE_HW_INTRINSICS

enum HWIntrinsicCategory : unsigned int
{
    // Simple SIMD intrinsics
    // - take Vector128/256<T> parameters
    // - return a Vector128/256<T>
    // - the codegen of overloads can be determined by intrinsicID and base type of returned vector
    HW_Category_SimpleSIMD,

    // IsSupported Property
    // - each ISA class has an "IsSupported" property
    HW_Category_IsSupportedProperty,

    // IMM intrinsics
    // - some SIMD intrinsics requires immediate value (i.e. imm8) to generate instruction
    HW_Category_IMM,

    // Scalar intrinsics
    // - operate over general purpose registers, like crc32, lzcnt, popcnt, etc.
    HW_Category_Scalar,

    // SIMD scalar
    // - operate over vector registers(XMM), but just compute on the first element
    HW_Category_SIMDScalar,

    // Memory access intrinsics
    // - e.g., Avx.Load, Avx.Store, Sse.LoadAligned
    HW_Category_MemoryLoad,
    HW_Category_MemoryStore,

    // Helper intrinsics
    // - do not directly correspond to a instruction, such as Avx.SetAllVector256
    HW_Category_Helper,

    // Special intrinsics
    // - have to be addressed specially
    HW_Category_Special
};

enum HWIntrinsicFlag : unsigned int
{
    HW_Flag_NoFlag = 0,

    // Commutative
    // - if a binary-op intrinsic is commutative (e.g., Add, Multiply), its op1 can be contained
    HW_Flag_Commutative = 0x1,

    // Full range IMM intrinsic
    // - the immediate value is valid on the full range of imm8 (0-255)
    HW_Flag_FullRangeIMM = 0x2,

    // Generic
    // - must throw NotSupportException if the type argument is not numeric type
    HW_Flag_OneTypeGeneric = 0x4,
    // Two-type Generic
    // - the intrinsic has two type parameters
    HW_Flag_TwoTypeGeneric = 0x8,

    // NoCodeGen
    // - should be transformed in the compiler front-end, cannot reach CodeGen
    HW_Flag_NoCodeGen = 0x10,

    // Unfixed SIMD-size
    // - overloaded on multiple vector sizes (SIMD size in the table is unreliable)
    HW_Flag_UnfixedSIMDSize = 0x20,

    // Complex overload
    // - the codegen of overloads cannot be determined by intrinsicID and base type
    HW_Flag_ComplexOverloads = 0x40,

    // Multi-instruction
    // - that one intrinsic can generate multiple instructions
    HW_Flag_MultiIns = 0x80,

    // NoContainment
    // the intrinsic cannot be contained
    HW_Flag_NoContainment = 0x100,

    // Copy Upper bits
    // some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand
    HW_Flag_CopyUpperBits = 0x200,

    // Select base type using the first argument type
    HW_Flag_BaseTypeFromFirstArg = 0x400,

    // Indicates compFloatingPointUsed does not need to be set.
    HW_Flag_NoFloatingPointUsed = 0x800,

    // Maybe IMM
    // the intrinsic has either imm or Vector overloads
    HW_Flag_MaybeIMM = 0x1000,

    // NoJmpTable IMM
    // the imm intrinsic does not need jumptable fallback when it gets non-const argument
    HW_Flag_NoJmpTableIMM = 0x2000,

    // 64-bit intrinsics
    // Intrinsics that operate over 64-bit general purpose registers are not supported on 32-bit platform
    HW_Flag_64BitOnly           = 0x4000,
    HW_Flag_SecondArgMaybe64Bit = 0x8000,

    // Select base type using the second argument type
    HW_Flag_BaseTypeFromSecondArg = 0x10000,

    // Special codegen
    // the intrinsics need special rules in CodeGen,
    // but may be table-driven in the front-end
    HW_Flag_SpecialCodeGen = 0x20000,

    // No Read/Modify/Write Semantics
    // the intrinsic doesn't have read/modify/write semantics in two/three-operand form.
    HW_Flag_NoRMWSemantics = 0x40000,

    // Special import
    // the intrinsics need special rules in importer,
    // but may be table-driven in the back-end
    HW_Flag_SpecialImport = 0x80000,
};

struct HWIntrinsicInfo
{
    NamedIntrinsic          id;
    const char*             name;
    InstructionSet          isa;
    int                     ival;
    unsigned                simdSize;
    int                     numArgs;
    instruction             ins[10];
    HWIntrinsicCategory     category;
    HWIntrinsicFlag         flags;

    static const HWIntrinsicInfo& lookup(NamedIntrinsic id);

    static NamedIntrinsic lookupId(const char* className, const char* methodName);
    static InstructionSet lookupIsa(const char* className);

    static unsigned lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig);

    static int lookupNumArgs(const GenTreeHWIntrinsic* node);
    static GenTree* lookupLastOp(const GenTreeHWIntrinsic* node);
    static bool isImmOp(NamedIntrinsic id, const GenTree* op);

    static int lookupImmUpperBound(NamedIntrinsic id);

    static bool isFullyImplementedIsa(InstructionSet isa);
    static bool isScalarIsa(InstructionSet isa);

    // Member lookup

    static NamedIntrinsic lookupId(NamedIntrinsic id)
    {
        return lookup(id).id;
    }

    static const char* lookupName(NamedIntrinsic id)
    {
        return lookup(id).name;
    }

    static InstructionSet lookupIsa(NamedIntrinsic id)
    {
        return lookup(id).isa;
    }

    static int lookupIval(NamedIntrinsic id)
    {
        return lookup(id).ival;
    }

    static unsigned lookupSimdSize(NamedIntrinsic id)
    {
        return lookup(id).simdSize;
    }

    static int lookupNumArgs(NamedIntrinsic id)
    {
        return lookup(id).numArgs;
    }

    static instruction lookupIns(NamedIntrinsic id, var_types type)
    {
        assert((type >= TYP_BYTE) && (type <= TYP_DOUBLE));
        return lookup(id).ins[type - TYP_BYTE];
    }

    static HWIntrinsicCategory lookupCategory(NamedIntrinsic id)
    {
        return lookup(id).category;
    }

    static HWIntrinsicFlag lookupFlags(NamedIntrinsic id)
    {
        return lookup(id).flags;
    }
};

#endif // FEATURE_HW_INTRINSICS

#endif // _HW_INTRINSIC_XARCH_H_