• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_INTRINSICS_COMMON_TO_X86_INTRINSICS_BINDINGS_H_
18 #define BERBERIS_INTRINSICS_COMMON_TO_X86_INTRINSICS_BINDINGS_H_
19 
20 #include <xmmintrin.h>
21 
22 #include <cstdint>
23 
24 #include "berberis/base/dependent_false.h"
25 #include "berberis/intrinsics/intrinsics_args.h"
26 #include "berberis/intrinsics/type_traits.h"
27 
28 namespace berberis::intrinsics::bindings {
29 
30 class Imm2 {
31  public:
32   using Type = int8_t;
33   static constexpr bool kIsImmediate = true;
34 };
35 
36 class Imm8 {
37  public:
38   using Type = int8_t;
39   static constexpr bool kIsImmediate = true;
40 };
41 
42 class Imm16 {
43  public:
44   using Type = int16_t;
45   static constexpr bool kIsImmediate = true;
46 };
47 
48 class Imm32 {
49  public:
50   using Type = int32_t;
51   static constexpr bool kIsImmediate = true;
52 };
53 
54 class Imm64 {
55  public:
56   using Type = int64_t;
57   static constexpr bool kIsImmediate = true;
58 };
59 
60 class AL {
61  public:
62   using Type = uint8_t;
63   static constexpr bool kIsImmediate = false;
64   static constexpr bool kIsImplicitReg = true;
65   static constexpr char kAsRegister = 'a';
66 };
67 
68 class AX {
69  public:
70   using Type = uint16_t;
71   static constexpr bool kIsImmediate = false;
72   static constexpr bool kIsImplicitReg = true;
73   static constexpr char kAsRegister = 'a';
74 };
75 
76 class EAX {
77  public:
78   using Type = uint32_t;
79   static constexpr bool kIsImmediate = false;
80   static constexpr bool kIsImplicitReg = true;
81   static constexpr char kAsRegister = 'a';
82   template <typename MachineInsnArch>
83   static constexpr auto kRegClass = MachineInsnArch::kEAX;
84 };
85 
86 class RAX {
87  public:
88   using Type = uint32_t;
89   static constexpr bool kIsImmediate = false;
90   static constexpr bool kIsImplicitReg = true;
91   static constexpr char kAsRegister = 'a';
92   template <typename MachineInsnArch>
93   static constexpr auto kRegClass = MachineInsnArch::kRAX;
94 };
95 
96 class CL {
97  public:
98   using Type = uint8_t;
99   static constexpr bool kIsImmediate = false;
100   static constexpr bool kIsImplicitReg = true;
101   static constexpr char kAsRegister = 'c';
102   template <typename MachineInsnArch>
103   static constexpr auto kRegClass = MachineInsnArch::kCL;
104 };
105 
106 class CX {
107  public:
108   using Type = uint16_t;
109   static constexpr bool kIsImmediate = false;
110   static constexpr bool kIsImplicitReg = true;
111   static constexpr char kAsRegister = 'c';
112 };
113 
114 class ECX {
115  public:
116   using Type = uint32_t;
117   static constexpr bool kIsImmediate = false;
118   static constexpr bool kIsImplicitReg = true;
119   static constexpr char kAsRegister = 'c';
120   template <typename MachineInsnArch>
121   static constexpr auto kRegClass = MachineInsnArch::kECX;
122 };
123 
124 class RCX {
125  public:
126   using Type = uint32_t;
127   static constexpr bool kIsImmediate = false;
128   static constexpr bool kIsImplicitReg = true;
129   static constexpr char kAsRegister = 'c';
130   template <typename MachineInsnArch>
131   static constexpr auto kRegClass = MachineInsnArch::kRCX;
132 };
133 
134 class DL {
135  public:
136   using Type = uint8_t;
137   static constexpr bool kIsImmediate = false;
138   static constexpr bool kIsImplicitReg = true;
139   static constexpr char kAsRegister = 'd';
140 };
141 
142 class DX {
143  public:
144   using Type = uint16_t;
145   static constexpr bool kIsImmediate = false;
146   static constexpr bool kIsImplicitReg = true;
147   static constexpr char kAsRegister = 'd';
148 };
149 
150 class EDX {
151  public:
152   using Type = uint32_t;
153   static constexpr bool kIsImmediate = false;
154   static constexpr bool kIsImplicitReg = true;
155   static constexpr char kAsRegister = 'd';
156   template <typename MachineInsnArch>
157   static constexpr auto kRegClass = MachineInsnArch::kEDX;
158 };
159 
160 class RDX {
161  public:
162   using Type = uint32_t;
163   static constexpr bool kIsImmediate = false;
164   static constexpr bool kIsImplicitReg = true;
165   static constexpr char kAsRegister = 'd';
166   template <typename MachineInsnArch>
167   static constexpr auto kRegClass = MachineInsnArch::kRDX;
168 };
169 
170 class GeneralReg8 {
171  public:
172   using Type = uint8_t;
173   static constexpr bool kIsImmediate = false;
174   static constexpr bool kIsImplicitReg = false;
175   static constexpr char kAsRegister = 'q';
176   template <typename MachineInsnArch>
177   static constexpr auto kRegClass = MachineInsnArch::kGeneralReg8;
178 };
179 
180 class GeneralReg16 {
181  public:
182   using Type = uint16_t;
183   static constexpr bool kIsImmediate = false;
184   static constexpr bool kIsImplicitReg = false;
185   static constexpr char kAsRegister = 'r';
186   template <typename MachineInsnArch>
187   static constexpr auto kRegClass = MachineInsnArch::kGeneralReg16;
188 };
189 
190 class GeneralReg32 {
191  public:
192   using Type = uint32_t;
193   static constexpr bool kIsImmediate = false;
194   static constexpr bool kIsImplicitReg = false;
195   static constexpr char kAsRegister = 'r';
196   template <typename MachineInsnArch>
197   static constexpr auto kRegClass = MachineInsnArch::kGeneralReg32;
198 };
199 
200 class GeneralReg64 {
201  public:
202   using Type = uint64_t;
203   static constexpr bool kIsImmediate = false;
204   static constexpr bool kIsImplicitReg = false;
205   static constexpr char kAsRegister = 'r';
206   template <typename MachineInsnArch>
207   static constexpr auto kRegClass = MachineInsnArch::kGeneralReg64;
208 };
209 
210 class FLAGS {
211  public:
212   static constexpr bool kIsImmediate = false;
213   static constexpr bool kIsImplicitReg = true;
214   static constexpr char kAsRegister = 0;
215   template <typename MachineInsnArch>
216   static constexpr auto kRegClass = MachineInsnArch::kFLAGS;
217 };
218 
219 class FpReg32 {
220  public:
221   using Type = __m128;
222   static constexpr bool kIsImmediate = false;
223   static constexpr bool kIsImplicitReg = false;
224   static constexpr char kAsRegister = 'x';
225   template <typename MachineInsnArch>
226   static constexpr auto kRegClass = MachineInsnArch::kFpReg32;
227 };
228 
229 class FpReg64 {
230  public:
231   using Type = __m128;
232   static constexpr bool kIsImmediate = false;
233   static constexpr bool kIsImplicitReg = false;
234   static constexpr char kAsRegister = 'x';
235   template <typename MachineInsnArch>
236   static constexpr auto kRegClass = MachineInsnArch::kFpReg64;
237 };
238 
239 class VecReg128 {
240  public:
241   using Type = __m128;
242   static constexpr bool kIsImmediate = false;
243   static constexpr bool kIsImplicitReg = false;
244   static constexpr char kAsRegister = 'x';
245   template <typename MachineInsnArch>
246   static constexpr auto kRegClass = MachineInsnArch::kVecReg128;
247 };
248 
249 class XmmReg {
250  public:
251   using Type = __m128;
252   static constexpr bool kIsImmediate = false;
253   static constexpr bool kIsImplicitReg = false;
254   static constexpr char kAsRegister = 'x';
255   template <typename MachineInsnArch>
256   static constexpr auto kRegClass = MachineInsnArch::kXmmReg;
257 };
258 
259 class Mem8 {
260  public:
261   using Type = uint8_t;
262   static constexpr bool kIsImmediate = false;
263   static constexpr char kAsRegister = 'm';
264 };
265 
266 class Mem16 {
267  public:
268   using Type = uint16_t;
269   static constexpr bool kIsImmediate = false;
270   static constexpr char kAsRegister = 'm';
271 };
272 
273 class Mem32 {
274  public:
275   using Type = uint32_t;
276   static constexpr bool kIsImmediate = false;
277   static constexpr char kAsRegister = 'm';
278 };
279 
280 class Mem64 {
281  public:
282   using Type = uint64_t;
283   static constexpr bool kIsImmediate = false;
284   static constexpr char kAsRegister = 'm';
285 };
286 
287 class MemX87 {
288  public:
289   static constexpr bool kIsImmediate = false;
290   static constexpr char kAsRegister = 'm';
291 };
292 
293 // // Tag classes. They are never instantioned, only used as tags to pass information about
294 // bindings.
295 class Def;
296 class DefEarlyClobber;
297 class Use;
298 class UseDef;
299 
300 template <typename Tag, typename MachineRegKind>
ToRegKind()301 constexpr auto ToRegKind() {
302   if constexpr (std::is_same_v<Tag, Def>) {
303     return MachineRegKind::kDef;
304   } else if constexpr (std::is_same_v<Tag, DefEarlyClobber>) {
305     return MachineRegKind::kDefEarlyClobber;
306   } else if constexpr (std::is_same_v<Tag, Use>) {
307     return MachineRegKind::kUse;
308   } else if constexpr (std::is_same_v<Tag, UseDef>) {
309     return MachineRegKind::kUseDef;
310   } else {
311     static_assert(kDependentTypeFalse<Tag>);
312   }
313 }
314 
315 template <typename Tag, typename MachineRegKind>
316 inline constexpr auto kRegKind = ToRegKind<Tag, MachineRegKind>();
317 
318 enum CPUIDRestriction : int {
319   kNoCPUIDRestriction = 0,
320   kHas3DNOW,
321   kHas3DNOWP,
322   kHasADX,
323   kHasAES,
324   kHasAESAVX,
325   kHasAMXBF16,
326   kHasAMXFP16,
327   kHasAMXINT8,
328   kHasAMXTILE,
329   kHasAVX,
330   kHasAVX2,
331   kHasAVX5124FMAPS,
332   kHasAVX5124VNNIW,
333   kHasAVX512BF16,
334   kHasAVX512BITALG,
335   kHasAVX512BW,
336   kHasAVX512CD,
337   kHasAVX512DQ,
338   kHasAVX512ER,
339   kHasAVX512F,
340   kHasAVX512FP16,
341   kHasAVX512IFMA,
342   kHasAVX512PF,
343   kHasAVX512VBMI,
344   kHasAVX512VBMI2,
345   kHasAVX512VL,
346   kHasAVX512VNNI,
347   kHasAVX512VPOPCNTDQ,
348   kHasBMI,
349   kHasBMI2,
350   kHasCLMUL,
351   kHasCMOV,
352   kHasCMPXCHG16B,
353   kHasCMPXCHG8B,
354   kHasF16C,
355   kHasFMA,
356   kHasFMA4,
357   kHasFXSAVE,
358   kHasLZCNT,
359   // BMI2 is set and PDEP/PEXT are ok to use. See more here:
360   //   https://twitter.com/instlatx64/status/1322503571288559617
361   kHashPDEP,
362   kHasPOPCNT,
363   kHasRDSEED,
364   kHasSERIALIZE,
365   kHasSHA,
366   kHasSSE,
367   kHasSSE2,
368   kHasSSE3,
369   kHasSSE4_1,
370   kHasSSE4_2,
371   kHasSSE4a,
372   kHasSSSE3,
373   kHasTBM,
374   kHasVAES,
375   kHasX87,
376   kIsAuthenticAMD
377 };
378 
379 enum PreciseNanOperationsHandling : int {
380   kNoNansOperation = 0,
381   kPreciseNanOperationsHandling,
382   kImpreciseNanOperationsHandling
383 };
384 
385 template <auto kIntrinsicTemplateName,
386           auto kMacroInstructionTemplateName,
387           auto kMnemo,
388           typename GetOpcode,
389           CPUIDRestriction kCPUIDRestrictionTemplateValue,
390           PreciseNanOperationsHandling kPreciseNanOperationsHandlingTemplateValue,
391           bool kSideEffectsTemplateValue,
392           typename... Types>
393 class AsmCallInfo;
394 
395 template <auto kIntrinsicTemplateName,
396           auto kMacroInstructionTemplateName,
397           auto kMnemo,
398           typename GetOpcode,
399           CPUIDRestriction kCPUIDRestrictionTemplateValue,
400           PreciseNanOperationsHandling kPreciseNanOperationsHandlingTemplateValue,
401           bool kSideEffectsTemplateValue,
402           typename... InputArgumentsTypes,
403           typename... OutputArgumentsTypes,
404           typename... BindingsTypes>
405 class AsmCallInfo<kIntrinsicTemplateName,
406                   kMacroInstructionTemplateName,
407                   kMnemo,
408                   GetOpcode,
409                   kCPUIDRestrictionTemplateValue,
410                   kPreciseNanOperationsHandlingTemplateValue,
411                   kSideEffectsTemplateValue,
412                   std::tuple<InputArgumentsTypes...>,
413                   std::tuple<OutputArgumentsTypes...>,
414                   BindingsTypes...>
415     final {
416  public:
417   static constexpr auto kIntrinsic = kIntrinsicTemplateName;
418   static constexpr auto kMacroInstruction = kMacroInstructionTemplateName;
419   // TODO(b/260725458): Use lambda template argument after C++20 becomes available.
420   template <typename Opcode>
421   static constexpr auto kOpcode = GetOpcode{}.template operator()<Opcode>();
422   static constexpr CPUIDRestriction kCPUIDRestriction = kCPUIDRestrictionTemplateValue;
423   static constexpr PreciseNanOperationsHandling kPreciseNanOperationsHandling =
424       kPreciseNanOperationsHandlingTemplateValue;
425   static constexpr bool kSideEffects = kSideEffectsTemplateValue;
426   static constexpr const char* InputArgumentsTypeNames[] = {
427       TypeTraits<InputArgumentsTypes>::kName...};
428   static constexpr const char* OutputArgumentsTypeNames[] = {
429       TypeTraits<OutputArgumentsTypes>::kName...};
430   template <typename Callback, typename... Args>
ProcessBindings(Callback && callback,Args &&...args)431   constexpr static void ProcessBindings(Callback&& callback, Args&&... args) {
432     (callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...), ...);
433   }
434   template <typename Callback, typename... Args>
MakeTuplefromBindings(Callback && callback,Args &&...args)435   constexpr static auto MakeTuplefromBindings(Callback&& callback, Args&&... args) {
436     return std::tuple_cat(callback(ArgTraits<BindingsTypes>(), std::forward<Args>(args)...)...);
437   }
438   using InputArguments = std::tuple<InputArgumentsTypes...>;
439   using OutputArguments = std::tuple<OutputArgumentsTypes...>;
440   using Bindings = std::tuple<BindingsTypes...>;
441   using IntrinsicType = std::conditional_t<std::tuple_size_v<OutputArguments> == 0,
442                                            void (*)(InputArgumentsTypes...),
443                                            OutputArguments (*)(InputArgumentsTypes...)>;
444   template <template <typename, auto, auto, typename...> typename MachineInsnType,
445             template <typename...>
446             typename ConstructorArgs,
447             typename Opcode>
448   using MachineInsn = MachineInsnType<AsmCallInfo,
449                                       kMnemo,
450                                       kOpcode<Opcode>,
451                                       ConstructorArgs<BindingsTypes...>,
452                                       BindingsTypes...>;
453 };
454 
455 }  // namespace berberis::intrinsics::bindings
456 
457 #endif  // BERBERIS_INTRINSICS_COMMON_TO_X86_INTRINSICS_BINDINGS_H_
458