1/*
2 * Copyright (C) 2011 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 ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
18#define ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
19
20#include <android-base/logging.h>
21
22#include "constants_arm.h"
23#include "debug/dwarf/register.h"
24#include "utils/managed_register.h"
25
26// TODO(VIXL): Make VIXL compile with -Wshadow.
27#pragma GCC diagnostic push
28#pragma GCC diagnostic ignored "-Wshadow"
29#include "aarch32/macro-assembler-aarch32.h"
30#pragma GCC diagnostic pop
31
32namespace art {
33namespace arm {
34
35// Values for register pairs.
36enum RegisterPair {
37  R0_R1 = 0,
38  R2_R3 = 1,
39  R4_R5 = 2,
40  R6_R7 = 3,
41  R1_R2 = 4,  // Dalvik style passing
42  kNumberOfRegisterPairs = 5,
43  kNoRegisterPair = -1,
44};
45
46std::ostream& operator<<(std::ostream& os, const RegisterPair& reg);
47
48const int kNumberOfCoreRegIds = kNumberOfCoreRegisters;
49const int kNumberOfCoreAllocIds = kNumberOfCoreRegisters;
50
51const int kNumberOfSRegIds = kNumberOfSRegisters;
52const int kNumberOfSAllocIds = kNumberOfSRegisters;
53
54const int kNumberOfDRegIds = kNumberOfDRegisters;
55const int kNumberOfOverlappingDRegIds = kNumberOfOverlappingDRegisters;
56const int kNumberOfDAllocIds = kNumberOfDRegIds - kNumberOfOverlappingDRegIds;
57
58const int kNumberOfPairRegIds = kNumberOfRegisterPairs;
59
60const int kNumberOfRegIds = kNumberOfCoreRegIds + kNumberOfSRegIds +
61    kNumberOfDRegIds + kNumberOfPairRegIds;
62const int kNumberOfAllocIds =
63    kNumberOfCoreAllocIds + kNumberOfSAllocIds + kNumberOfDAllocIds;
64
65// Register ids map:
66//   [0..R[  core registers (enum Register)
67//   [R..S[  single precision VFP registers (enum SRegister)
68//   [S..D[  double precision VFP registers (enum DRegister)
69//   [D..P[  core register pairs (enum RegisterPair)
70// where
71//   R = kNumberOfCoreRegIds
72//   S = R + kNumberOfSRegIds
73//   D = S + kNumberOfDRegIds
74//   P = D + kNumberOfRegisterPairs
75
76// Allocation ids map:
77//   [0..R[  core registers (enum Register)
78//   [R..S[  single precision VFP registers (enum SRegister)
79//   [S..N[  non-overlapping double precision VFP registers (16-31 in enum
80//           DRegister, VFPv3-D32 only)
81// where
82//   R = kNumberOfCoreAllocIds
83//   S = R + kNumberOfSAllocIds
84//   N = S + kNumberOfDAllocIds
85
86
87// An instance of class 'ManagedRegister' represents a single ARM register or a
88// pair of core ARM registers (enum RegisterPair). A single register is either a
89// core register (enum Register), a VFP single precision register
90// (enum SRegister), or a VFP double precision register (enum DRegister).
91// 'ManagedRegister::NoRegister()' returns an invalid ManagedRegister.
92// There is a one-to-one mapping between ManagedRegister and register id.
93class ArmManagedRegister : public ManagedRegister {
94 public:
95  constexpr Register AsCoreRegister() const {
96    CHECK(IsCoreRegister());
97    return static_cast<Register>(id_);
98  }
99
100  vixl::aarch32::Register AsVIXLRegister() const {
101    CHECK(IsCoreRegister());
102    return vixl::aarch32::Register(id_);
103  }
104
105  constexpr SRegister AsSRegister() const {
106    CHECK(IsSRegister());
107    return static_cast<SRegister>(id_ - kNumberOfCoreRegIds);
108  }
109
110  vixl::aarch32::SRegister AsVIXLSRegister() const {
111    CHECK(IsSRegister());
112    return vixl::aarch32::SRegister(id_ - kNumberOfCoreRegIds);
113  }
114
115  constexpr DRegister AsDRegister() const {
116    CHECK(IsDRegister());
117    return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
118  }
119
120  vixl::aarch32::DRegister AsVIXLDRegister() const {
121    CHECK(IsDRegister());
122    return vixl::aarch32::DRegister(id_ - kNumberOfCoreRegIds - kNumberOfSRegIds);
123  }
124
125  constexpr SRegister AsOverlappingDRegisterLow() const {
126    CHECK(IsOverlappingDRegister());
127    DRegister d_reg = AsDRegister();
128    return static_cast<SRegister>(d_reg * 2);
129  }
130
131  constexpr SRegister AsOverlappingDRegisterHigh() const {
132    CHECK(IsOverlappingDRegister());
133    DRegister d_reg = AsDRegister();
134    return static_cast<SRegister>(d_reg * 2 + 1);
135  }
136
137  constexpr RegisterPair AsRegisterPair() const {
138    CHECK(IsRegisterPair());
139    Register reg_low = AsRegisterPairLow();
140    if (reg_low == R1) {
141      return R1_R2;
142    } else {
143      return static_cast<RegisterPair>(reg_low / 2);
144    }
145  }
146
147  constexpr Register AsRegisterPairLow() const {
148    CHECK(IsRegisterPair());
149    // Appropriate mapping of register ids allows to use AllocIdLow().
150    return FromRegId(AllocIdLow()).AsCoreRegister();
151  }
152
153  vixl::aarch32::Register AsVIXLRegisterPairLow() const {
154    return vixl::aarch32::Register(AsRegisterPairLow());
155  }
156
157  constexpr Register AsRegisterPairHigh() const {
158    CHECK(IsRegisterPair());
159    // Appropriate mapping of register ids allows to use AllocIdHigh().
160    return FromRegId(AllocIdHigh()).AsCoreRegister();
161  }
162
163  vixl::aarch32::Register AsVIXLRegisterPairHigh() const {
164    return vixl::aarch32::Register(AsRegisterPairHigh());
165  }
166
167  constexpr bool IsCoreRegister() const {
168    CHECK(IsValidManagedRegister());
169    return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
170  }
171
172  constexpr bool IsSRegister() const {
173    CHECK(IsValidManagedRegister());
174    const int test = id_ - kNumberOfCoreRegIds;
175    return (0 <= test) && (test < kNumberOfSRegIds);
176  }
177
178  constexpr bool IsDRegister() const {
179    CHECK(IsValidManagedRegister());
180    const int test = id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds);
181    return (0 <= test) && (test < kNumberOfDRegIds);
182  }
183
184  // Returns true if this DRegister overlaps SRegisters.
185  constexpr bool IsOverlappingDRegister() const {
186    CHECK(IsValidManagedRegister());
187    const int test = id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds);
188    return (0 <= test) && (test < kNumberOfOverlappingDRegIds);
189  }
190
191  constexpr bool IsRegisterPair() const {
192    CHECK(IsValidManagedRegister());
193    const int test =
194        id_ - (kNumberOfCoreRegIds + kNumberOfSRegIds + kNumberOfDRegIds);
195    return (0 <= test) && (test < kNumberOfPairRegIds);
196  }
197
198  constexpr bool IsSameType(ArmManagedRegister test) const {
199    CHECK(IsValidManagedRegister() && test.IsValidManagedRegister());
200    return
201      (IsCoreRegister() && test.IsCoreRegister()) ||
202      (IsSRegister() && test.IsSRegister()) ||
203      (IsDRegister() && test.IsDRegister()) ||
204      (IsRegisterPair() && test.IsRegisterPair());
205  }
206
207
208  // Returns true if the two managed-registers ('this' and 'other') overlap.
209  // Either managed-register may be the NoRegister. If both are the NoRegister
210  // then false is returned.
211  bool Overlaps(const ArmManagedRegister& other) const;
212
213  void Print(std::ostream& os) const;
214
215  static constexpr ArmManagedRegister FromCoreRegister(Register r) {
216    CHECK_NE(r, kNoRegister);
217    return FromRegId(r);
218  }
219
220  static constexpr ArmManagedRegister FromSRegister(SRegister r) {
221    CHECK_NE(r, kNoSRegister);
222    return FromRegId(r + kNumberOfCoreRegIds);
223  }
224
225  static constexpr ArmManagedRegister FromDRegister(DRegister r) {
226    CHECK_NE(r, kNoDRegister);
227    return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfSRegIds));
228  }
229
230  static constexpr ArmManagedRegister FromRegisterPair(RegisterPair r) {
231    CHECK_NE(r, kNoRegisterPair);
232    return FromRegId(r + (kNumberOfCoreRegIds +
233                          kNumberOfSRegIds + kNumberOfDRegIds));
234  }
235
236  // Return a RegisterPair consisting of Register r_low and r_low + 1.
237  static constexpr ArmManagedRegister FromCoreRegisterPair(Register r_low) {
238    if (r_low != R1) {  // not the dalvik special case
239      CHECK_NE(r_low, kNoRegister);
240      CHECK_EQ(0, (r_low % 2));
241      const int r = r_low / 2;
242      CHECK_LT(r, kNumberOfPairRegIds);
243      return FromRegisterPair(static_cast<RegisterPair>(r));
244    } else {
245      return FromRegisterPair(R1_R2);
246    }
247  }
248
249  // Return a DRegister overlapping SRegister r_low and r_low + 1.
250  static constexpr ArmManagedRegister FromSRegisterPair(SRegister r_low) {
251    CHECK_NE(r_low, kNoSRegister);
252    CHECK_EQ(0, (r_low % 2));
253    const int r = r_low / 2;
254    CHECK_LT(r, kNumberOfOverlappingDRegIds);
255    return FromDRegister(static_cast<DRegister>(r));
256  }
257
258 private:
259  constexpr bool IsValidManagedRegister() const {
260    return (0 <= id_) && (id_ < kNumberOfRegIds);
261  }
262
263  int RegId() const {
264    CHECK(!IsNoRegister());
265    return id_;
266  }
267
268  int AllocId() const {
269    CHECK(IsValidManagedRegister() &&
270           !IsOverlappingDRegister() && !IsRegisterPair());
271    int r = id_;
272    if ((kNumberOfDAllocIds > 0) && IsDRegister()) {  // VFPv3-D32 only.
273      r -= kNumberOfOverlappingDRegIds;
274    }
275    CHECK_LT(r, kNumberOfAllocIds);
276    return r;
277  }
278
279  int AllocIdLow() const;
280  int AllocIdHigh() const;
281
282  friend class ManagedRegister;
283
284  explicit constexpr ArmManagedRegister(int reg_id) : ManagedRegister(reg_id) {}
285
286  static constexpr ArmManagedRegister FromRegId(int reg_id) {
287    ArmManagedRegister reg(reg_id);
288    CHECK(reg.IsValidManagedRegister());
289    return reg;
290  }
291};
292
293std::ostream& operator<<(std::ostream& os, const ArmManagedRegister& reg);
294
295}  // namespace arm
296
297constexpr inline arm::ArmManagedRegister ManagedRegister::AsArm() const {
298  arm::ArmManagedRegister reg(id_);
299  CHECK(reg.IsNoRegister() || reg.IsValidManagedRegister());
300  return reg;
301}
302
303}  // namespace art
304
305#endif  // ART_COMPILER_UTILS_ARM_MANAGED_REGISTER_ARM_H_
306