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