xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceRegistersX8664.h (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1 //===- subzero/src/IceRegistersX8664.h - Register information ---*- C++ -*-===//
2 //
3 //                        The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Declares the registers and their encodings for x86-64.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef SUBZERO_SRC_ICEREGISTERSX8664_H
16 #define SUBZERO_SRC_ICEREGISTERSX8664_H
17 
18 #include "IceBitVector.h"
19 #include "IceDefs.h"
20 #include "IceInstX8664.def"
21 #include "IceTargetLowering.h"
22 #include "IceTargetLoweringX86RegClass.h"
23 #include "IceTypes.h"
24 
25 #include <initializer_list>
26 
27 namespace Ice {
28 using namespace ::Ice::X86;
29 
30 class RegX8664 {
31 public:
32   /// An enum of every register. The enum value may not match the encoding used
33   /// to binary encode register operands in instructions.
34   enum AllRegisters {
35 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
36           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
37           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
38   val,
39     REGX8664_TABLE
40 #undef X
41         Reg_NUM
42   };
43 
44   /// An enum of GPR Registers. The enum value does match the encoding used to
45   /// binary encode register operands in instructions.
46   enum GPRRegister {
47 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
48           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
49           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
50   Encoded_##val = encode,
51     REGX8664_GPR_TABLE
52 #undef X
53         Encoded_Not_GPR = -1
54   };
55 
56   /// An enum of XMM Registers. The enum value does match the encoding used to
57   /// binary encode register operands in instructions.
58   enum XmmRegister {
59 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
60           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
61           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
62   Encoded_##val = encode,
63     REGX8664_XMM_TABLE
64 #undef X
65         Encoded_Not_Xmm = -1
66   };
67 
68   /// An enum of Byte Registers. The enum value does match the encoding used to
69   /// binary encode register operands in instructions.
70   enum ByteRegister {
71 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
72           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
73           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
74   Encoded_8_##val = encode,
75     REGX8664_BYTEREG_TABLE
76 #undef X
77         Encoded_Not_ByteReg = -1
78   };
79 
getRegName(RegNumT RegNum)80   static inline const char *getRegName(RegNumT RegNum) {
81     static const char *const RegNames[Reg_NUM] = {
82 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
83           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
84           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
85   name,
86         REGX8664_TABLE
87 #undef X
88     };
89     RegNum.assertIsValid();
90     return RegNames[RegNum];
91   }
92 
getEncodedGPR(RegNumT RegNum)93   static inline GPRRegister getEncodedGPR(RegNumT RegNum) {
94     static const GPRRegister GPRRegs[Reg_NUM] = {
95 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
96           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
97           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
98   GPRRegister(isGPR ? encode : GPRRegister::Encoded_Not_GPR),
99         REGX8664_TABLE
100 #undef X
101     };
102     RegNum.assertIsValid();
103     assert(GPRRegs[RegNum] != GPRRegister::Encoded_Not_GPR);
104     return GPRRegs[RegNum];
105   }
106 
getEncodedByteReg(RegNumT RegNum)107   static inline ByteRegister getEncodedByteReg(RegNumT RegNum) {
108     static const ByteRegister ByteRegs[Reg_NUM] = {
109 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
110           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
111           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
112   ByteRegister(is8 ? encode : ByteRegister::Encoded_Not_ByteReg),
113         REGX8664_TABLE
114 #undef X
115     };
116     RegNum.assertIsValid();
117     assert(ByteRegs[RegNum] != ByteRegister::Encoded_Not_ByteReg);
118     return ByteRegs[RegNum];
119   }
120 
isXmm(RegNumT RegNum)121   static inline bool isXmm(RegNumT RegNum) {
122     static const bool IsXmm[Reg_NUM] = {
123 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
124           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
125           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
126   isXmm,
127         REGX8664_TABLE
128 #undef X
129     };
130     return IsXmm[RegNum];
131   }
132 
getEncodedXmm(RegNumT RegNum)133   static inline XmmRegister getEncodedXmm(RegNumT RegNum) {
134     static const XmmRegister XmmRegs[Reg_NUM] = {
135 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
136           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
137           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
138   XmmRegister(isXmm ? encode : XmmRegister::Encoded_Not_Xmm),
139         REGX8664_TABLE
140 #undef X
141     };
142     RegNum.assertIsValid();
143     assert(XmmRegs[RegNum] != XmmRegister::Encoded_Not_Xmm);
144     return XmmRegs[RegNum];
145   }
146 
getEncoding(RegNumT RegNum)147   static inline uint32_t getEncoding(RegNumT RegNum) {
148     static const uint32_t Encoding[Reg_NUM] = {
149 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
150           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
151           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
152   encode,
153         REGX8664_TABLE
154 #undef X
155     };
156     RegNum.assertIsValid();
157     return Encoding[RegNum];
158   }
159 
getBaseReg(RegNumT RegNum)160   static inline RegNumT getBaseReg(RegNumT RegNum) {
161     static const RegNumT BaseRegs[Reg_NUM] = {
162 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
163           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
164           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
165   base,
166         REGX8664_TABLE
167 #undef X
168     };
169     RegNum.assertIsValid();
170     return BaseRegs[RegNum];
171   }
172 
173 private:
getFirstGprForType(Type Ty)174   static inline RegNumT getFirstGprForType(Type Ty) {
175     switch (Ty) {
176     default:
177       llvm_unreachable("Invalid type for GPR.");
178     case IceType_i1:
179     case IceType_i8:
180       return Reg_al;
181     case IceType_i16:
182       return Reg_ax;
183     case IceType_i32:
184       return Reg_eax;
185     case IceType_i64:
186       return Reg_rax;
187     }
188   }
189 
190 public:
getGprForType(Type Ty,RegNumT RegNum)191   static inline RegNumT getGprForType(Type Ty, RegNumT RegNum) {
192     assert(RegNum.hasValue());
193 
194     if (!isScalarIntegerType(Ty)) {
195       return RegNum;
196     }
197 
198     assert(Ty == IceType_i1 || Ty == IceType_i8 || Ty == IceType_i16 ||
199            Ty == IceType_i32 || Ty == IceType_i64);
200 
201     if (RegNum == Reg_ah) {
202       assert(Ty == IceType_i8);
203       return RegNum;
204     }
205 
206     assert(RegNum != Reg_bh);
207     assert(RegNum != Reg_ch);
208     assert(RegNum != Reg_dh);
209 
210     const RegNumT FirstGprForType = getFirstGprForType(Ty);
211 
212     switch (RegNum) {
213     default:
214       llvm::report_fatal_error("Unknown register.");
215 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
216           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
217           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
218   case val: {                                                                  \
219     if (!isGPR)                                                                \
220       return val;                                                              \
221     assert((is64) || (is32) || (is16) || (is8) || getBaseReg(val) == Reg_rsp); \
222     constexpr AllRegisters FirstGprWithRegNumSize =                            \
223         ((is64) || val == Reg_rsp)                                             \
224             ? Reg_rax                                                          \
225             : (((is32) || val == Reg_esp)                                      \
226                    ? Reg_eax                                                   \
227                    : (((is16) || val == Reg_sp) ? Reg_ax : Reg_al));           \
228     const auto NewRegNum =                                                     \
229         RegNumT::fixme(RegNum - FirstGprWithRegNumSize + FirstGprForType);     \
230     assert(getBaseReg(RegNum) == getBaseReg(NewRegNum) &&                      \
231            "Error involving " #val);                                           \
232     return NewRegNum;                                                          \
233   }
234       REGX8664_TABLE
235 #undef X
236     }
237   }
238 
239   static inline void
initRegisterSet(const::Ice::ClFlags & Flags,std::array<SmallBitVector,RCX86_NUM> * TypeToRegisterSet,std::array<SmallBitVector,Reg_NUM> * RegisterAliases)240   initRegisterSet(const ::Ice::ClFlags &Flags,
241                   std::array<SmallBitVector, RCX86_NUM> *TypeToRegisterSet,
242                   std::array<SmallBitVector, Reg_NUM> *RegisterAliases) {
243     SmallBitVector IntegerRegistersI64(Reg_NUM);
244     SmallBitVector IntegerRegistersI32(Reg_NUM);
245     SmallBitVector IntegerRegistersI16(Reg_NUM);
246     SmallBitVector IntegerRegistersI8(Reg_NUM);
247     SmallBitVector FloatRegisters(Reg_NUM);
248     SmallBitVector VectorRegisters(Reg_NUM);
249     SmallBitVector Trunc64To8Registers(Reg_NUM);
250     SmallBitVector Trunc32To8Registers(Reg_NUM);
251     SmallBitVector Trunc16To8Registers(Reg_NUM);
252     SmallBitVector Trunc8RcvrRegisters(Reg_NUM);
253     SmallBitVector AhRcvrRegisters(Reg_NUM);
254     SmallBitVector InvalidRegisters(Reg_NUM);
255 
256     static constexpr struct {
257       uint16_t Val;
258       unsigned IsReservedWhenSandboxing : 1;
259       unsigned Is64 : 1;
260       unsigned Is32 : 1;
261       unsigned Is16 : 1;
262       unsigned Is8 : 1;
263       unsigned IsXmm : 1;
264       unsigned Is64To8 : 1;
265       unsigned Is32To8 : 1;
266       unsigned Is16To8 : 1;
267       unsigned IsTrunc8Rcvr : 1;
268       unsigned IsAhRcvr : 1;
269 #define NUM_ALIASES_BITS 2
270       SizeT NumAliases : (NUM_ALIASES_BITS + 1);
271       uint16_t Aliases[1 << NUM_ALIASES_BITS];
272 #undef NUM_ALIASES_BITS
273     } X8664RegTable[Reg_NUM] = {
274 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
275           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
276           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
277   {                                                                            \
278       val,                                                                     \
279       sboxres,                                                                 \
280       is64,                                                                    \
281       is32,                                                                    \
282       is16,                                                                    \
283       is8,                                                                     \
284       isXmm,                                                                   \
285       is64To8,                                                                 \
286       is32To8,                                                                 \
287       is16To8,                                                                 \
288       isTrunc8Rcvr,                                                            \
289       isAhRcvr,                                                                \
290       (std::initializer_list<uint16_t> aliases).size(),                        \
291       aliases,                                                                 \
292   },
293         REGX8664_TABLE
294 #undef X
295     };
296 
297     for (SizeT ii = 0; ii < llvm::array_lengthof(X8664RegTable); ++ii) {
298       const auto &Entry = X8664RegTable[ii];
299       // Even though the register is disabled for register allocation, it might
300       // still be used by the Target Lowering (e.g., base pointer), so the
301       // register alias table still needs to be defined.
302       (*RegisterAliases)[Entry.Val].resize(Reg_NUM);
303       for (Ice::SizeT J = 0; J < Entry.NumAliases; ++J) {
304         SizeT Alias = Entry.Aliases[J];
305         assert(!(*RegisterAliases)[Entry.Val][Alias] && "Duplicate alias");
306         (*RegisterAliases)[Entry.Val].set(Alias);
307       }
308 
309       (*RegisterAliases)[Entry.Val].set(Entry.Val);
310 
311       (IntegerRegistersI64)[Entry.Val] = Entry.Is64;
312       (IntegerRegistersI32)[Entry.Val] = Entry.Is32;
313       (IntegerRegistersI16)[Entry.Val] = Entry.Is16;
314       (IntegerRegistersI8)[Entry.Val] = Entry.Is8;
315       (FloatRegisters)[Entry.Val] = Entry.IsXmm;
316       (VectorRegisters)[Entry.Val] = Entry.IsXmm;
317       (Trunc64To8Registers)[Entry.Val] = Entry.Is64To8;
318       (Trunc32To8Registers)[Entry.Val] = Entry.Is32To8;
319       (Trunc16To8Registers)[Entry.Val] = Entry.Is16To8;
320       (Trunc8RcvrRegisters)[Entry.Val] = Entry.IsTrunc8Rcvr;
321       (AhRcvrRegisters)[Entry.Val] = Entry.IsAhRcvr;
322     }
323 
324     (*TypeToRegisterSet)[RC_void] = InvalidRegisters;
325     (*TypeToRegisterSet)[RC_i1] = IntegerRegistersI8;
326     (*TypeToRegisterSet)[RC_i8] = IntegerRegistersI8;
327     (*TypeToRegisterSet)[RC_i16] = IntegerRegistersI16;
328     (*TypeToRegisterSet)[RC_i32] = IntegerRegistersI32;
329     (*TypeToRegisterSet)[RC_i64] = IntegerRegistersI64;
330     (*TypeToRegisterSet)[RC_f32] = FloatRegisters;
331     (*TypeToRegisterSet)[RC_f64] = FloatRegisters;
332     (*TypeToRegisterSet)[RC_v4i1] = VectorRegisters;
333     (*TypeToRegisterSet)[RC_v8i1] = VectorRegisters;
334     (*TypeToRegisterSet)[RC_v16i1] = VectorRegisters;
335     (*TypeToRegisterSet)[RC_v16i8] = VectorRegisters;
336     (*TypeToRegisterSet)[RC_v8i16] = VectorRegisters;
337     (*TypeToRegisterSet)[RC_v4i32] = VectorRegisters;
338     (*TypeToRegisterSet)[RC_v4f32] = VectorRegisters;
339     (*TypeToRegisterSet)[RCX86_Is64To8] = Trunc64To8Registers;
340     (*TypeToRegisterSet)[RCX86_Is32To8] = Trunc32To8Registers;
341     (*TypeToRegisterSet)[RCX86_Is16To8] = Trunc16To8Registers;
342     (*TypeToRegisterSet)[RCX86_IsTrunc8Rcvr] = Trunc8RcvrRegisters;
343     (*TypeToRegisterSet)[RCX86_IsAhRcvr] = AhRcvrRegisters;
344   }
345 
346   static inline SmallBitVector
getRegisterSet(const::Ice::ClFlags & Flags,TargetLowering::RegSetMask Include,TargetLowering::RegSetMask Exclude)347   getRegisterSet(const ::Ice::ClFlags &Flags,
348                  TargetLowering::RegSetMask Include,
349                  TargetLowering::RegSetMask Exclude) {
350     SmallBitVector Registers(Reg_NUM);
351 
352 #define X(val, encode, name, base, scratch, preserved, stackptr, frameptr,     \
353           sboxres, isGPR, is64, is32, is16, is8, isXmm, is64To8, is32To8,      \
354           is16To8, isTrunc8Rcvr, isAhRcvr, aliases)                            \
355   if (scratch && (Include & TargetLowering::RegSet_CallerSave))                \
356     Registers[val] = true;                                                     \
357   if (preserved && (Include & TargetLowering::RegSet_CalleeSave))              \
358     Registers[val] = true;                                                     \
359   if (stackptr && (Include & TargetLowering::RegSet_StackPointer))             \
360     Registers[val] = true;                                                     \
361   if (frameptr && (Include & TargetLowering::RegSet_FramePointer))             \
362     Registers[val] = true;                                                     \
363   if (scratch && (Exclude & TargetLowering::RegSet_CallerSave))                \
364     Registers[val] = false;                                                    \
365   if (preserved && (Exclude & TargetLowering::RegSet_CalleeSave))              \
366     Registers[val] = false;                                                    \
367   if (stackptr && (Exclude & TargetLowering::RegSet_StackPointer))             \
368     Registers[val] = false;                                                    \
369   if (frameptr && (Exclude & TargetLowering::RegSet_FramePointer))             \
370     Registers[val] = false;
371 
372     REGX8664_TABLE
373 
374 #undef X
375 
376     return Registers;
377   }
378 
379 #if defined(_WIN64)
380   // Microsoft x86-64 calling convention:
381   //
382   // * The first four arguments of vector/fp type, regardless of their
383   // position relative to the other arguments in the argument list, are placed
384   // in registers %xmm0 - %xmm3.
385   //
386   // * The first four arguments of integer types, regardless of their position
387   // relative to the other arguments in the argument list, are placed in
388   // registers %rcx, %rdx, %r8, and %r9.
389 
390   /// The maximum number of arguments to pass in XMM registers
391   static constexpr uint32_t X86_MAX_XMM_ARGS = 4;
392   /// The maximum number of arguments to pass in GPR registers
393   static constexpr uint32_t X86_MAX_GPR_ARGS = 4;
getRegisterForGprArgNum(Type Ty,uint32_t ArgNum)394   static inline RegNumT getRegisterForGprArgNum(Type Ty, uint32_t ArgNum) {
395     if (ArgNum >= X86_MAX_GPR_ARGS) {
396       return RegNumT();
397     }
398     static const AllRegisters GprForArgNum[] = {
399         Reg_rcx,
400         Reg_rdx,
401         Reg_r8,
402         Reg_r9,
403     };
404     static_assert(llvm::array_lengthof(GprForArgNum) == X86_MAX_GPR_ARGS,
405                   "Mismatch between MAX_GPR_ARGS and GprForArgNum.");
406     assert(Ty == IceType_i64 || Ty == IceType_i32);
407     return RegX8664::getGprForType(Ty, GprForArgNum[ArgNum]);
408   }
409   // Given the absolute argument position and argument position by type, return
410   // the register index to assign it to.
getArgIndex(SizeT argPos,SizeT argPosByType)411   static inline SizeT getArgIndex(SizeT argPos, SizeT argPosByType) {
412     // Microsoft x64 ABI: register is selected by arg position (e.g. 1st int as
413     // 2nd param goes into 2nd int reg)
414     (void)argPosByType;
415     return argPos;
416   };
417 
418 #else
419   // System V x86-64 calling convention:
420   //
421   // * The first eight arguments of vector/fp type, regardless of their
422   // position relative to the other arguments in the argument list, are placed
423   // in registers %xmm0 - %xmm7.
424   //
425   // * The first six arguments of integer types, regardless of their position
426   // relative to the other arguments in the argument list, are placed in
427   // registers %rdi, %rsi, %rdx, %rcx, %r8, and %r9.
428   //
429   // This intends to match the section "Function Calling Sequence" of the
430   // document "System V Application Binary Interface."
431 
432   /// The maximum number of arguments to pass in XMM registers
433   static constexpr uint32_t X86_MAX_XMM_ARGS = 8;
434   /// The maximum number of arguments to pass in GPR registers
435   static constexpr uint32_t X86_MAX_GPR_ARGS = 6;
436   /// Get the register for a given argument slot in the GPRs.
getRegisterForGprArgNum(Type Ty,uint32_t ArgNum)437   static inline RegNumT getRegisterForGprArgNum(Type Ty, uint32_t ArgNum) {
438     if (ArgNum >= X86_MAX_GPR_ARGS) {
439       return RegNumT();
440     }
441     static const AllRegisters GprForArgNum[] = {
442         Reg_rdi, Reg_rsi, Reg_rdx, Reg_rcx, Reg_r8, Reg_r9,
443     };
444     static_assert(llvm::array_lengthof(GprForArgNum) == X86_MAX_GPR_ARGS,
445                   "Mismatch between MAX_GPR_ARGS and GprForArgNum.");
446     assert(Ty == IceType_i64 || Ty == IceType_i32);
447     return RegX8664::getGprForType(Ty, GprForArgNum[ArgNum]);
448   }
449   // Given the absolute argument position and argument position by type, return
450   // the register index to assign it to.
getArgIndex(SizeT argPos,SizeT argPosByType)451   static inline SizeT getArgIndex(SizeT argPos, SizeT argPosByType) {
452     (void)argPos;
453     return argPosByType;
454   }
455 #endif
456 
457   /// Get the register for a given argument slot in the XMM registers.
getRegisterForXmmArgNum(uint32_t ArgNum)458   static inline RegNumT getRegisterForXmmArgNum(uint32_t ArgNum) {
459     // TODO(sehr): Change to use the CCArg technique used in ARM32.
460     static_assert(Reg_xmm0 + 1 == Reg_xmm1,
461                   "Inconsistency between XMM register numbers and ordinals");
462     if (ArgNum >= X86_MAX_XMM_ARGS) {
463       return RegNumT();
464     }
465     return RegNumT::fixme(Reg_xmm0 + ArgNum);
466   }
467 };
468 
469 } // end of namespace Ice
470 
471 #endif // SUBZERO_SRC_ICEREGISTERSX8664_H
472