1 | //===-- RISCVBaseInfo.h - Top level definitions for RISC-V MC ---*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains small standalone enum definitions for the RISC-V target |
10 | // useful for the compiler back-end and the MC libraries. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | #ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H |
14 | #define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVBASEINFO_H |
15 | |
16 | #include "MCTargetDesc/RISCVMCTargetDesc.h" |
17 | #include "llvm/ADT/APFloat.h" |
18 | #include "llvm/ADT/APInt.h" |
19 | #include "llvm/ADT/StringRef.h" |
20 | #include "llvm/ADT/StringSwitch.h" |
21 | #include "llvm/MC/MCInstrDesc.h" |
22 | #include "llvm/TargetParser/RISCVISAInfo.h" |
23 | #include "llvm/TargetParser/RISCVTargetParser.h" |
24 | #include "llvm/TargetParser/SubtargetFeature.h" |
25 | |
26 | namespace llvm { |
27 | |
28 | // RISCVII - This namespace holds all of the target specific flags that |
29 | // instruction info tracks. All definitions must match RISCVInstrFormats.td. |
30 | namespace RISCVII { |
31 | enum { |
32 | InstFormatPseudo = 0, |
33 | InstFormatR = 1, |
34 | InstFormatR4 = 2, |
35 | InstFormatI = 3, |
36 | InstFormatS = 4, |
37 | InstFormatB = 5, |
38 | InstFormatU = 6, |
39 | InstFormatJ = 7, |
40 | InstFormatCR = 8, |
41 | InstFormatCI = 9, |
42 | InstFormatCSS = 10, |
43 | InstFormatCIW = 11, |
44 | InstFormatCL = 12, |
45 | InstFormatCS = 13, |
46 | InstFormatCA = 14, |
47 | InstFormatCB = 15, |
48 | InstFormatCJ = 16, |
49 | InstFormatCU = 17, |
50 | InstFormatCLB = 18, |
51 | InstFormatCLH = 19, |
52 | InstFormatCSB = 20, |
53 | InstFormatCSH = 21, |
54 | InstFormatOther = 22, |
55 | |
56 | InstFormatMask = 31, |
57 | InstFormatShift = 0, |
58 | |
59 | ConstraintShift = InstFormatShift + 5, |
60 | VS2Constraint = 0b001 << ConstraintShift, |
61 | VS1Constraint = 0b010 << ConstraintShift, |
62 | VMConstraint = 0b100 << ConstraintShift, |
63 | ConstraintMask = 0b111 << ConstraintShift, |
64 | |
65 | VLMulShift = ConstraintShift + 3, |
66 | VLMulMask = 0b111 << VLMulShift, |
67 | |
68 | // Force a tail agnostic policy even this instruction has a tied destination. |
69 | ForceTailAgnosticShift = VLMulShift + 3, |
70 | ForceTailAgnosticMask = 1 << ForceTailAgnosticShift, |
71 | |
72 | // Is this a _TIED vector pseudo instruction. For these instructions we |
73 | // shouldn't skip the tied operand when converting to MC instructions. |
74 | IsTiedPseudoShift = ForceTailAgnosticShift + 1, |
75 | IsTiedPseudoMask = 1 << IsTiedPseudoShift, |
76 | |
77 | // Does this instruction have a SEW operand. It will be the last explicit |
78 | // operand unless there is a vector policy operand. Used by RVV Pseudos. |
79 | HasSEWOpShift = IsTiedPseudoShift + 1, |
80 | HasSEWOpMask = 1 << HasSEWOpShift, |
81 | |
82 | // Does this instruction have a VL operand. It will be the second to last |
83 | // explicit operand unless there is a vector policy operand. Used by RVV |
84 | // Pseudos. |
85 | HasVLOpShift = HasSEWOpShift + 1, |
86 | HasVLOpMask = 1 << HasVLOpShift, |
87 | |
88 | // Does this instruction have a vector policy operand. It will be the last |
89 | // explicit operand. Used by RVV Pseudos. |
90 | HasVecPolicyOpShift = HasVLOpShift + 1, |
91 | HasVecPolicyOpMask = 1 << HasVecPolicyOpShift, |
92 | |
93 | // Is this instruction a vector widening reduction instruction. Used by RVV |
94 | // Pseudos. |
95 | IsRVVWideningReductionShift = HasVecPolicyOpShift + 1, |
96 | IsRVVWideningReductionMask = 1 << IsRVVWideningReductionShift, |
97 | |
98 | // Does this instruction care about mask policy. If it is not, the mask policy |
99 | // could be either agnostic or undisturbed. For example, unmasked, store, and |
100 | // reduction operations result would not be affected by mask policy, so |
101 | // compiler has free to select either one. |
102 | UsesMaskPolicyShift = IsRVVWideningReductionShift + 1, |
103 | UsesMaskPolicyMask = 1 << UsesMaskPolicyShift, |
104 | |
105 | // Indicates that the result can be considered sign extended from bit 31. Some |
106 | // instructions with this flag aren't W instructions, but are either sign |
107 | // extended from a smaller size, always outputs a small integer, or put zeros |
108 | // in bits 63:31. Used by the SExtWRemoval pass. |
109 | IsSignExtendingOpWShift = UsesMaskPolicyShift + 1, |
110 | IsSignExtendingOpWMask = 1ULL << IsSignExtendingOpWShift, |
111 | |
112 | HasRoundModeOpShift = IsSignExtendingOpWShift + 1, |
113 | HasRoundModeOpMask = 1 << HasRoundModeOpShift, |
114 | |
115 | UsesVXRMShift = HasRoundModeOpShift + 1, |
116 | UsesVXRMMask = 1 << UsesVXRMShift, |
117 | |
118 | // Indicates whether these instructions can partially overlap between source |
119 | // registers and destination registers according to the vector spec. |
120 | // 0 -> not a vector pseudo |
121 | // 1 -> default value for vector pseudos. not widening or narrowing. |
122 | // 2 -> narrowing case |
123 | // 3 -> widening case |
124 | TargetOverlapConstraintTypeShift = UsesVXRMShift + 1, |
125 | TargetOverlapConstraintTypeMask = 3ULL << TargetOverlapConstraintTypeShift, |
126 | }; |
127 | |
128 | // Helper functions to read TSFlags. |
129 | /// \returns the format of the instruction. |
130 | static inline unsigned getFormat(uint64_t TSFlags) { |
131 | return (TSFlags & InstFormatMask) >> InstFormatShift; |
132 | } |
133 | /// \returns the LMUL for the instruction. |
134 | static inline VLMUL getLMul(uint64_t TSFlags) { |
135 | return static_cast<VLMUL>((TSFlags & VLMulMask) >> VLMulShift); |
136 | } |
137 | /// \returns true if tail agnostic is enforced for the instruction. |
138 | static inline bool doesForceTailAgnostic(uint64_t TSFlags) { |
139 | return TSFlags & ForceTailAgnosticMask; |
140 | } |
141 | /// \returns true if this a _TIED pseudo. |
142 | static inline bool isTiedPseudo(uint64_t TSFlags) { |
143 | return TSFlags & IsTiedPseudoMask; |
144 | } |
145 | /// \returns true if there is a SEW operand for the instruction. |
146 | static inline bool hasSEWOp(uint64_t TSFlags) { |
147 | return TSFlags & HasSEWOpMask; |
148 | } |
149 | /// \returns true if there is a VL operand for the instruction. |
150 | static inline bool hasVLOp(uint64_t TSFlags) { |
151 | return TSFlags & HasVLOpMask; |
152 | } |
153 | /// \returns true if there is a vector policy operand for this instruction. |
154 | static inline bool hasVecPolicyOp(uint64_t TSFlags) { |
155 | return TSFlags & HasVecPolicyOpMask; |
156 | } |
157 | /// \returns true if it is a vector widening reduction instruction. |
158 | static inline bool isRVVWideningReduction(uint64_t TSFlags) { |
159 | return TSFlags & IsRVVWideningReductionMask; |
160 | } |
161 | /// \returns true if mask policy is valid for the instruction. |
162 | static inline bool usesMaskPolicy(uint64_t TSFlags) { |
163 | return TSFlags & UsesMaskPolicyMask; |
164 | } |
165 | |
166 | /// \returns true if there is a rounding mode operand for this instruction |
167 | static inline bool hasRoundModeOp(uint64_t TSFlags) { |
168 | return TSFlags & HasRoundModeOpMask; |
169 | } |
170 | |
171 | /// \returns true if this instruction uses vxrm |
172 | static inline bool usesVXRM(uint64_t TSFlags) { return TSFlags & UsesVXRMMask; } |
173 | |
174 | static inline unsigned getVLOpNum(const MCInstrDesc &Desc) { |
175 | const uint64_t TSFlags = Desc.TSFlags; |
176 | // This method is only called if we expect to have a VL operand, and all |
177 | // instructions with VL also have SEW. |
178 | assert(hasSEWOp(TSFlags) && hasVLOp(TSFlags)); |
179 | unsigned Offset = 2; |
180 | if (hasVecPolicyOp(TSFlags)) |
181 | Offset = 3; |
182 | return Desc.getNumOperands() - Offset; |
183 | } |
184 | |
185 | static inline unsigned getSEWOpNum(const MCInstrDesc &Desc) { |
186 | const uint64_t TSFlags = Desc.TSFlags; |
187 | assert(hasSEWOp(TSFlags)); |
188 | unsigned Offset = 1; |
189 | if (hasVecPolicyOp(TSFlags)) |
190 | Offset = 2; |
191 | return Desc.getNumOperands() - Offset; |
192 | } |
193 | |
194 | static inline unsigned getVecPolicyOpNum(const MCInstrDesc &Desc) { |
195 | assert(hasVecPolicyOp(Desc.TSFlags)); |
196 | return Desc.getNumOperands() - 1; |
197 | } |
198 | |
199 | /// \returns the index to the rounding mode immediate value if any, otherwise |
200 | /// returns -1. |
201 | static inline int getFRMOpNum(const MCInstrDesc &Desc) { |
202 | const uint64_t TSFlags = Desc.TSFlags; |
203 | if (!hasRoundModeOp(TSFlags) || usesVXRM(TSFlags)) |
204 | return -1; |
205 | |
206 | // The operand order |
207 | // -------------------------------------- |
208 | // | n-1 (if any) | n-2 | n-3 | n-4 | |
209 | // | policy | sew | vl | frm | |
210 | // -------------------------------------- |
211 | return getVLOpNum(Desc) - 1; |
212 | } |
213 | |
214 | /// \returns the index to the rounding mode immediate value if any, otherwise |
215 | /// returns -1. |
216 | static inline int getVXRMOpNum(const MCInstrDesc &Desc) { |
217 | const uint64_t TSFlags = Desc.TSFlags; |
218 | if (!hasRoundModeOp(TSFlags) || !usesVXRM(TSFlags)) |
219 | return -1; |
220 | // The operand order |
221 | // -------------------------------------- |
222 | // | n-1 (if any) | n-2 | n-3 | n-4 | |
223 | // | policy | sew | vl | vxrm | |
224 | // -------------------------------------- |
225 | return getVLOpNum(Desc) - 1; |
226 | } |
227 | |
228 | // Is the first def operand tied to the first use operand. This is true for |
229 | // vector pseudo instructions that have a merge operand for tail/mask |
230 | // undisturbed. It's also true for vector FMA instructions where one of the |
231 | // operands is also the destination register. |
232 | static inline bool isFirstDefTiedToFirstUse(const MCInstrDesc &Desc) { |
233 | return Desc.getNumDefs() < Desc.getNumOperands() && |
234 | Desc.getOperandConstraint(OpNum: Desc.getNumDefs(), Constraint: MCOI::TIED_TO) == 0; |
235 | } |
236 | |
237 | // RISC-V Specific Machine Operand Flags |
238 | enum { |
239 | MO_None = 0, |
240 | MO_CALL = 1, |
241 | MO_LO = 3, |
242 | MO_HI = 4, |
243 | MO_PCREL_LO = 5, |
244 | MO_PCREL_HI = 6, |
245 | MO_GOT_HI = 7, |
246 | MO_TPREL_LO = 8, |
247 | MO_TPREL_HI = 9, |
248 | MO_TPREL_ADD = 10, |
249 | MO_TLS_GOT_HI = 11, |
250 | MO_TLS_GD_HI = 12, |
251 | MO_TLSDESC_HI = 13, |
252 | MO_TLSDESC_LOAD_LO = 14, |
253 | MO_TLSDESC_ADD_LO = 15, |
254 | MO_TLSDESC_CALL = 16, |
255 | |
256 | // Used to differentiate between target-specific "direct" flags and "bitmask" |
257 | // flags. A machine operand can only have one "direct" flag, but can have |
258 | // multiple "bitmask" flags. |
259 | MO_DIRECT_FLAG_MASK = 31 |
260 | }; |
261 | } // namespace RISCVII |
262 | |
263 | namespace RISCVOp { |
264 | enum OperandType : unsigned { |
265 | OPERAND_FIRST_RISCV_IMM = MCOI::OPERAND_FIRST_TARGET, |
266 | OPERAND_UIMM1 = OPERAND_FIRST_RISCV_IMM, |
267 | OPERAND_UIMM2, |
268 | OPERAND_UIMM2_LSB0, |
269 | OPERAND_UIMM3, |
270 | OPERAND_UIMM4, |
271 | OPERAND_UIMM5, |
272 | OPERAND_UIMM5_LSB0, |
273 | OPERAND_UIMM6, |
274 | OPERAND_UIMM6_LSB0, |
275 | OPERAND_UIMM7, |
276 | OPERAND_UIMM7_LSB00, |
277 | OPERAND_UIMM8_LSB00, |
278 | OPERAND_UIMM8, |
279 | OPERAND_UIMM8_LSB000, |
280 | OPERAND_UIMM8_GE32, |
281 | OPERAND_UIMM9_LSB000, |
282 | OPERAND_UIMM10_LSB00_NONZERO, |
283 | OPERAND_UIMM12, |
284 | OPERAND_UIMM16, |
285 | OPERAND_UIMM32, |
286 | OPERAND_ZERO, |
287 | OPERAND_SIMM5, |
288 | OPERAND_SIMM5_PLUS1, |
289 | OPERAND_SIMM6, |
290 | OPERAND_SIMM6_NONZERO, |
291 | OPERAND_SIMM10_LSB0000_NONZERO, |
292 | OPERAND_SIMM12, |
293 | OPERAND_SIMM12_LSB00000, |
294 | OPERAND_UIMM20, |
295 | OPERAND_UIMMLOG2XLEN, |
296 | OPERAND_UIMMLOG2XLEN_NONZERO, |
297 | OPERAND_CLUI_IMM, |
298 | OPERAND_VTYPEI10, |
299 | OPERAND_VTYPEI11, |
300 | OPERAND_RVKRNUM, |
301 | OPERAND_RVKRNUM_0_7, |
302 | OPERAND_RVKRNUM_1_10, |
303 | OPERAND_RVKRNUM_2_14, |
304 | OPERAND_SPIMM, |
305 | OPERAND_LAST_RISCV_IMM = OPERAND_SPIMM, |
306 | // Operand is either a register or uimm5, this is used by V extension pseudo |
307 | // instructions to represent a value that be passed as AVL to either vsetvli |
308 | // or vsetivli. |
309 | OPERAND_AVL, |
310 | }; |
311 | } // namespace RISCVOp |
312 | |
313 | // Describes the predecessor/successor bits used in the FENCE instruction. |
314 | namespace RISCVFenceField { |
315 | enum FenceField { |
316 | I = 8, |
317 | O = 4, |
318 | R = 2, |
319 | W = 1 |
320 | }; |
321 | } |
322 | |
323 | // Describes the supported floating point rounding mode encodings. |
324 | namespace RISCVFPRndMode { |
325 | enum RoundingMode { |
326 | RNE = 0, |
327 | RTZ = 1, |
328 | RDN = 2, |
329 | RUP = 3, |
330 | RMM = 4, |
331 | DYN = 7, |
332 | Invalid |
333 | }; |
334 | |
335 | inline static StringRef roundingModeToString(RoundingMode RndMode) { |
336 | switch (RndMode) { |
337 | default: |
338 | llvm_unreachable("Unknown floating point rounding mode" ); |
339 | case RISCVFPRndMode::RNE: |
340 | return "rne" ; |
341 | case RISCVFPRndMode::RTZ: |
342 | return "rtz" ; |
343 | case RISCVFPRndMode::RDN: |
344 | return "rdn" ; |
345 | case RISCVFPRndMode::RUP: |
346 | return "rup" ; |
347 | case RISCVFPRndMode::RMM: |
348 | return "rmm" ; |
349 | case RISCVFPRndMode::DYN: |
350 | return "dyn" ; |
351 | } |
352 | } |
353 | |
354 | inline static RoundingMode stringToRoundingMode(StringRef Str) { |
355 | return StringSwitch<RoundingMode>(Str) |
356 | .Case(S: "rne" , Value: RISCVFPRndMode::RNE) |
357 | .Case(S: "rtz" , Value: RISCVFPRndMode::RTZ) |
358 | .Case(S: "rdn" , Value: RISCVFPRndMode::RDN) |
359 | .Case(S: "rup" , Value: RISCVFPRndMode::RUP) |
360 | .Case(S: "rmm" , Value: RISCVFPRndMode::RMM) |
361 | .Case(S: "dyn" , Value: RISCVFPRndMode::DYN) |
362 | .Default(Value: RISCVFPRndMode::Invalid); |
363 | } |
364 | |
365 | inline static bool isValidRoundingMode(unsigned Mode) { |
366 | switch (Mode) { |
367 | default: |
368 | return false; |
369 | case RISCVFPRndMode::RNE: |
370 | case RISCVFPRndMode::RTZ: |
371 | case RISCVFPRndMode::RDN: |
372 | case RISCVFPRndMode::RUP: |
373 | case RISCVFPRndMode::RMM: |
374 | case RISCVFPRndMode::DYN: |
375 | return true; |
376 | } |
377 | } |
378 | } // namespace RISCVFPRndMode |
379 | |
380 | namespace RISCVVXRndMode { |
381 | enum RoundingMode { |
382 | RNU = 0, |
383 | RNE = 1, |
384 | RDN = 2, |
385 | ROD = 3, |
386 | }; |
387 | } // namespace RISCVVXRndMode |
388 | |
389 | //===----------------------------------------------------------------------===// |
390 | // Floating-point Immediates |
391 | // |
392 | |
393 | namespace RISCVLoadFPImm { |
394 | float getFPImm(unsigned Imm); |
395 | |
396 | /// getLoadFPImm - Return a 5-bit binary encoding of the floating-point |
397 | /// immediate value. If the value cannot be represented as a 5-bit binary |
398 | /// encoding, then return -1. |
399 | int getLoadFPImm(APFloat FPImm); |
400 | } // namespace RISCVLoadFPImm |
401 | |
402 | namespace RISCVSysReg { |
403 | struct SysReg { |
404 | const char *Name; |
405 | const char *AltName; |
406 | const char *DeprecatedName; |
407 | unsigned Encoding; |
408 | // FIXME: add these additional fields when needed. |
409 | // Privilege Access: Read, Write, Read-Only. |
410 | // unsigned ReadWrite; |
411 | // Privilege Mode: User, System or Machine. |
412 | // unsigned Mode; |
413 | // Check field name. |
414 | // unsigned Extra; |
415 | // Register number without the privilege bits. |
416 | // unsigned Number; |
417 | FeatureBitset FeaturesRequired; |
418 | bool isRV32Only; |
419 | |
420 | bool haveRequiredFeatures(const FeatureBitset &ActiveFeatures) const { |
421 | // Not in 32-bit mode. |
422 | if (isRV32Only && ActiveFeatures[RISCV::Feature64Bit]) |
423 | return false; |
424 | // No required feature associated with the system register. |
425 | if (FeaturesRequired.none()) |
426 | return true; |
427 | return (FeaturesRequired & ActiveFeatures) == FeaturesRequired; |
428 | } |
429 | }; |
430 | |
431 | #define GET_SysRegsList_DECL |
432 | #include "RISCVGenSearchableTables.inc" |
433 | } // end namespace RISCVSysReg |
434 | |
435 | namespace RISCVInsnOpcode { |
436 | struct RISCVOpcode { |
437 | const char *Name; |
438 | unsigned Value; |
439 | }; |
440 | |
441 | #define GET_RISCVOpcodesList_DECL |
442 | #include "RISCVGenSearchableTables.inc" |
443 | } // end namespace RISCVInsnOpcode |
444 | |
445 | namespace RISCVABI { |
446 | |
447 | enum ABI { |
448 | ABI_ILP32, |
449 | ABI_ILP32F, |
450 | ABI_ILP32D, |
451 | ABI_ILP32E, |
452 | ABI_LP64, |
453 | ABI_LP64F, |
454 | ABI_LP64D, |
455 | ABI_LP64E, |
456 | ABI_Unknown |
457 | }; |
458 | |
459 | // Returns the target ABI, or else a StringError if the requested ABIName is |
460 | // not supported for the given TT and FeatureBits combination. |
461 | ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits, |
462 | StringRef ABIName); |
463 | |
464 | ABI getTargetABI(StringRef ABIName); |
465 | |
466 | // Returns the register used to hold the stack pointer after realignment. |
467 | MCRegister getBPReg(); |
468 | |
469 | // Returns the register holding shadow call stack pointer. |
470 | MCRegister getSCSPReg(); |
471 | |
472 | } // namespace RISCVABI |
473 | |
474 | namespace RISCVFeatures { |
475 | |
476 | // Validates if the given combination of features are valid for the target |
477 | // triple. Exits with report_fatal_error if not. |
478 | void validate(const Triple &TT, const FeatureBitset &FeatureBits); |
479 | |
480 | llvm::Expected<std::unique_ptr<RISCVISAInfo>> |
481 | parseFeatureBits(bool IsRV64, const FeatureBitset &FeatureBits); |
482 | |
483 | } // namespace RISCVFeatures |
484 | |
485 | namespace RISCVRVC { |
486 | bool compress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI); |
487 | bool uncompress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI); |
488 | } // namespace RISCVRVC |
489 | |
490 | namespace RISCVZC { |
491 | enum RLISTENCODE { |
492 | RA = 4, |
493 | RA_S0, |
494 | RA_S0_S1, |
495 | RA_S0_S2, |
496 | RA_S0_S3, |
497 | RA_S0_S4, |
498 | RA_S0_S5, |
499 | RA_S0_S6, |
500 | RA_S0_S7, |
501 | RA_S0_S8, |
502 | RA_S0_S9, |
503 | // note - to include s10, s11 must also be included |
504 | RA_S0_S11, |
505 | INVALID_RLIST, |
506 | }; |
507 | |
508 | inline unsigned encodeRlist(MCRegister EndReg, bool IsRV32E = false) { |
509 | assert((!IsRV32E || EndReg <= RISCV::X9) && "Invalid Rlist for RV32E" ); |
510 | switch (EndReg) { |
511 | case RISCV::X1: |
512 | return RLISTENCODE::RA; |
513 | case RISCV::X8: |
514 | return RLISTENCODE::RA_S0; |
515 | case RISCV::X9: |
516 | return RLISTENCODE::RA_S0_S1; |
517 | case RISCV::X18: |
518 | return RLISTENCODE::RA_S0_S2; |
519 | case RISCV::X19: |
520 | return RLISTENCODE::RA_S0_S3; |
521 | case RISCV::X20: |
522 | return RLISTENCODE::RA_S0_S4; |
523 | case RISCV::X21: |
524 | return RLISTENCODE::RA_S0_S5; |
525 | case RISCV::X22: |
526 | return RLISTENCODE::RA_S0_S6; |
527 | case RISCV::X23: |
528 | return RLISTENCODE::RA_S0_S7; |
529 | case RISCV::X24: |
530 | return RLISTENCODE::RA_S0_S8; |
531 | case RISCV::X25: |
532 | return RLISTENCODE::RA_S0_S9; |
533 | case RISCV::X26: |
534 | return RLISTENCODE::INVALID_RLIST; |
535 | case RISCV::X27: |
536 | return RLISTENCODE::RA_S0_S11; |
537 | default: |
538 | llvm_unreachable("Undefined input." ); |
539 | } |
540 | } |
541 | |
542 | inline static unsigned getStackAdjBase(unsigned RlistVal, bool IsRV64) { |
543 | assert(RlistVal != RLISTENCODE::INVALID_RLIST && |
544 | "{ra, s0-s10} is not supported, s11 must be included." ); |
545 | if (!IsRV64) { |
546 | switch (RlistVal) { |
547 | case RLISTENCODE::RA: |
548 | case RLISTENCODE::RA_S0: |
549 | case RLISTENCODE::RA_S0_S1: |
550 | case RLISTENCODE::RA_S0_S2: |
551 | return 16; |
552 | case RLISTENCODE::RA_S0_S3: |
553 | case RLISTENCODE::RA_S0_S4: |
554 | case RLISTENCODE::RA_S0_S5: |
555 | case RLISTENCODE::RA_S0_S6: |
556 | return 32; |
557 | case RLISTENCODE::RA_S0_S7: |
558 | case RLISTENCODE::RA_S0_S8: |
559 | case RLISTENCODE::RA_S0_S9: |
560 | return 48; |
561 | case RLISTENCODE::RA_S0_S11: |
562 | return 64; |
563 | } |
564 | } else { |
565 | switch (RlistVal) { |
566 | case RLISTENCODE::RA: |
567 | case RLISTENCODE::RA_S0: |
568 | return 16; |
569 | case RLISTENCODE::RA_S0_S1: |
570 | case RLISTENCODE::RA_S0_S2: |
571 | return 32; |
572 | case RLISTENCODE::RA_S0_S3: |
573 | case RLISTENCODE::RA_S0_S4: |
574 | return 48; |
575 | case RLISTENCODE::RA_S0_S5: |
576 | case RLISTENCODE::RA_S0_S6: |
577 | return 64; |
578 | case RLISTENCODE::RA_S0_S7: |
579 | case RLISTENCODE::RA_S0_S8: |
580 | return 80; |
581 | case RLISTENCODE::RA_S0_S9: |
582 | return 96; |
583 | case RLISTENCODE::RA_S0_S11: |
584 | return 112; |
585 | } |
586 | } |
587 | llvm_unreachable("Unexpected RlistVal" ); |
588 | } |
589 | |
590 | inline static bool getSpimm(unsigned RlistVal, unsigned &SpimmVal, |
591 | int64_t StackAdjustment, bool IsRV64) { |
592 | if (RlistVal == RLISTENCODE::INVALID_RLIST) |
593 | return false; |
594 | unsigned StackAdjBase = getStackAdjBase(RlistVal, IsRV64); |
595 | StackAdjustment -= StackAdjBase; |
596 | if (StackAdjustment % 16 != 0) |
597 | return false; |
598 | SpimmVal = StackAdjustment / 16; |
599 | if (SpimmVal > 3) |
600 | return false; |
601 | return true; |
602 | } |
603 | |
604 | void printRlist(unsigned SlistEncode, raw_ostream &OS); |
605 | } // namespace RISCVZC |
606 | |
607 | } // namespace llvm |
608 | |
609 | #endif |
610 | |