1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_REGISTER_H_
6#define V8_REGISTER_H_
7
8#include "src/reglist.h"
9
10namespace v8 {
11
12namespace internal {
13
14// Base type for CPU Registers.
15//
16// 1) We would prefer to use an enum for registers, but enum values are
17// assignment-compatible with int, which has caused code-generation bugs.
18//
19// 2) By not using an enum, we are possibly preventing the compiler from
20// doing certain constant folds, which may significantly reduce the
21// code generated for some assembly instructions (because they boil down
22// to a few constants). If this is a problem, we could change the code
23// such that we use an enum in optimized mode, and the class in debug
24// mode. This way we get the compile-time error checking in debug mode
25// and best performance in optimized code.
26template <typename SubType, int kAfterLastRegister>
27class RegisterBase {
28 // Internal enum class; used for calling constexpr methods, where we need to
29 // pass an integral type as template parameter.
30 enum class RegisterCode : int { kFirst = 0, kAfterLast = kAfterLastRegister };
31
32 public:
33 static constexpr int kCode_no_reg = -1;
34 static constexpr int kNumRegisters = kAfterLastRegister;
35
36 static constexpr SubType no_reg() { return SubType{kCode_no_reg}; }
37
38 template <int code>
39 static constexpr SubType from_code() {
40 static_assert(code >= 0 && code < kNumRegisters, "must be valid reg code");
41 return SubType{code};
42 }
43
44 constexpr operator RegisterCode() const {
45 return static_cast<RegisterCode>(reg_code_);
46 }
47
48 template <RegisterCode reg_code>
49 static constexpr int code() {
50 static_assert(
51 reg_code >= RegisterCode::kFirst && reg_code < RegisterCode::kAfterLast,
52 "must be valid reg");
53 return static_cast<int>(reg_code);
54 }
55
56 template <RegisterCode reg_code>
57 static constexpr int is_valid() {
58 return static_cast<int>(reg_code) != kCode_no_reg;
59 }
60
61 template <RegisterCode reg_code>
62 static constexpr RegList bit() {
63 return is_valid<reg_code>() ? RegList{1} << code<reg_code>() : RegList{};
64 }
65
66 static SubType from_code(int code) {
67 DCHECK_LE(0, code);
68 DCHECK_GT(kNumRegisters, code);
69 return SubType{code};
70 }
71
72 // Constexpr version (pass registers as template parameters).
73 template <RegisterCode... reg_codes>
74 static constexpr RegList ListOf() {
75 return CombineRegLists(RegisterBase::bit<reg_codes>()...);
76 }
77
78 // Non-constexpr version (pass registers as method parameters).
79 template <typename... Register>
80 static RegList ListOf(Register... regs) {
81 return CombineRegLists(regs.bit()...);
82 }
83
84 constexpr bool is_valid() const { return reg_code_ != kCode_no_reg; }
85
86 int code() const {
87 DCHECK(is_valid());
88 return reg_code_;
89 }
90
91 RegList bit() const { return is_valid() ? RegList{1} << code() : RegList{}; }
92
93 inline constexpr bool operator==(SubType other) const {
94 return reg_code_ == other.reg_code_;
95 }
96 inline constexpr bool operator!=(SubType other) const {
97 return reg_code_ != other.reg_code_;
98 }
99
100 // Used to print the name of some special registers.
101 static const char* GetSpecialRegisterName(int code) { return "UNKNOWN"; }
102
103 protected:
104 explicit constexpr RegisterBase(int code) : reg_code_(code) {}
105 int reg_code_;
106};
107
108template <typename RegType,
109 typename = decltype(RegisterName(std::declval<RegType>()))>
110inline std::ostream& operator<<(std::ostream& os, RegType reg) {
111 return os << RegisterName(reg);
112}
113
114// Helper macros to define a {RegisterName} method based on a macro list
115// containing all names.
116#define DEFINE_REGISTER_NAMES_NAME(name) #name,
117#define DEFINE_REGISTER_NAMES(RegType, LIST) \
118 inline const char* RegisterName(RegType reg) { \
119 static constexpr const char* Names[] = {LIST(DEFINE_REGISTER_NAMES_NAME)}; \
120 STATIC_ASSERT(arraysize(Names) == RegType::kNumRegisters); \
121 return reg.is_valid() ? Names[reg.code()] : "invalid"; \
122 }
123
124} // namespace internal
125} // namespace v8
126#endif // V8_REGISTER_H_
127