Georgia Kouveli | 8b57c86 | 2017-03-02 15:18:58 +0000 | [diff] [blame] | 1 | // Copyright 2017, VIXL authors |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 2 | // All rights reserved. |
| 3 | // |
| 4 | // Redistribution and use in source and binary forms, with or without |
| 5 | // modification, are permitted provided that the following conditions are met: |
| 6 | // |
| 7 | // * Redistributions of source code must retain the above copyright notice, |
| 8 | // this list of conditions and the following disclaimer. |
| 9 | // * Redistributions in binary form must reproduce the above copyright notice, |
| 10 | // this list of conditions and the following disclaimer in the documentation |
| 11 | // and/or other materials provided with the distribution. |
| 12 | // * Neither the name of ARM Limited nor the names of its contributors may be |
| 13 | // used to endorse or promote products derived from this software without |
| 14 | // specific prior written permission. |
| 15 | // |
| 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND |
| 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
| 20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | |
| 27 | #ifndef VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_ |
| 28 | #define VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_ |
| 29 | |
Pierre Langlois | 78973f2 | 2016-08-10 14:35:56 +0100 | [diff] [blame] | 30 | extern "C" { |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 31 | #include <stdint.h> |
Pierre Langlois | 78973f2 | 2016-08-10 14:35:56 +0100 | [diff] [blame] | 32 | } |
| 33 | |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 34 | #include <algorithm> |
Pierre Langlois | 78973f2 | 2016-08-10 14:35:56 +0100 | [diff] [blame] | 35 | #include <ostream> |
| 36 | |
Vincent Belliard | 3e1b899 | 2016-07-13 16:02:19 -0700 | [diff] [blame] | 37 | #include "code-buffer-vixl.h" |
Pierre Langlois | 1bce007 | 2017-06-06 17:58:58 +0100 | [diff] [blame] | 38 | #include "utils-vixl.h" |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 39 | #include "aarch32/constants-aarch32.h" |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 40 | |
| 41 | #ifdef __arm__ |
| 42 | #define HARDFLOAT __attribute__((noinline, pcs("aapcs-vfp"))) |
| 43 | #else |
| 44 | #define HARDFLOAT __attribute__((noinline)) |
| 45 | #endif |
| 46 | |
| 47 | namespace vixl { |
| 48 | namespace aarch32 { |
| 49 | |
| 50 | class Operand; |
| 51 | class SOperand; |
| 52 | class DOperand; |
| 53 | class QOperand; |
| 54 | class MemOperand; |
| 55 | class AlignedMemOperand; |
| 56 | |
| 57 | enum AddrMode { Offset = 0, PreIndex = 1, PostIndex = 2 }; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 58 | |
| 59 | class CPURegister { |
| 60 | public: |
| 61 | enum RegisterType { |
| 62 | kNoRegister = 0, |
| 63 | kRRegister = 1, |
| 64 | kSRegister = 2, |
| 65 | kDRegister = 3, |
| 66 | kQRegister = 4 |
| 67 | }; |
| 68 | |
| 69 | private: |
| 70 | static const int kCodeBits = 5; |
| 71 | static const int kTypeBits = 4; |
| 72 | static const int kSizeBits = 8; |
| 73 | static const int kCodeShift = 0; |
| 74 | static const int kTypeShift = kCodeShift + kCodeBits; |
| 75 | static const int kSizeShift = kTypeShift + kTypeBits; |
| 76 | static const uint32_t kCodeMask = ((1 << kCodeBits) - 1) << kCodeShift; |
| 77 | static const uint32_t kTypeMask = ((1 << kTypeBits) - 1) << kTypeShift; |
| 78 | static const uint32_t kSizeMask = ((1 << kSizeBits) - 1) << kSizeShift; |
| 79 | uint32_t value_; |
| 80 | |
| 81 | public: |
| 82 | CPURegister(RegisterType type, uint32_t code, int size) |
| 83 | : value_((type << kTypeShift) | (code << kCodeShift) | |
| 84 | (size << kSizeShift)) { |
| 85 | #ifdef VIXL_DEBUG |
| 86 | switch (type) { |
| 87 | case kNoRegister: |
| 88 | break; |
| 89 | case kRRegister: |
| 90 | VIXL_ASSERT(code < kNumberOfRegisters); |
| 91 | VIXL_ASSERT(size == kRegSizeInBits); |
| 92 | break; |
| 93 | case kSRegister: |
| 94 | VIXL_ASSERT(code < kNumberOfSRegisters); |
| 95 | VIXL_ASSERT(size == kSRegSizeInBits); |
| 96 | break; |
| 97 | case kDRegister: |
| 98 | VIXL_ASSERT(code < kMaxNumberOfDRegisters); |
| 99 | VIXL_ASSERT(size == kDRegSizeInBits); |
| 100 | break; |
| 101 | case kQRegister: |
| 102 | VIXL_ASSERT(code < kNumberOfQRegisters); |
| 103 | VIXL_ASSERT(size == kQRegSizeInBits); |
| 104 | break; |
| 105 | default: |
| 106 | VIXL_UNREACHABLE(); |
| 107 | break; |
| 108 | } |
| 109 | #endif |
| 110 | } |
| 111 | RegisterType GetType() const { |
| 112 | return static_cast<RegisterType>((value_ & kTypeMask) >> kTypeShift); |
| 113 | } |
Vincent Belliard | f678618 | 2016-09-21 11:55:28 +0100 | [diff] [blame] | 114 | bool IsRegister() const { return GetType() == kRRegister; } |
| 115 | bool IsS() const { return GetType() == kSRegister; } |
| 116 | bool IsD() const { return GetType() == kDRegister; } |
| 117 | bool IsQ() const { return GetType() == kQRegister; } |
| 118 | bool IsVRegister() const { return IsS() || IsD() || IsQ(); } |
| 119 | bool IsFPRegister() const { return IsS() || IsD(); } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 120 | uint32_t GetCode() const { return (value_ & kCodeMask) >> kCodeShift; } |
| 121 | uint32_t GetReg() const { return value_; } |
| 122 | int GetSizeInBits() const { return (value_ & kSizeMask) >> kSizeShift; } |
| 123 | int GetRegSizeInBytes() const { |
| 124 | return (GetType() == kNoRegister) ? 0 : (GetSizeInBits() / 8); |
| 125 | } |
| 126 | bool Is64Bits() const { return GetSizeInBits() == 64; } |
| 127 | bool Is128Bits() const { return GetSizeInBits() == 128; } |
| 128 | bool IsSameFormat(CPURegister reg) { |
| 129 | return (value_ & ~kCodeMask) == (reg.value_ & ~kCodeMask); |
| 130 | } |
| 131 | bool Is(CPURegister ref) const { return GetReg() == ref.GetReg(); } |
| 132 | bool IsValid() const { return GetType() != kNoRegister; } |
| 133 | }; |
| 134 | |
| 135 | class Register : public CPURegister { |
| 136 | public: |
| 137 | Register() : CPURegister(kNoRegister, 0, kRegSizeInBits) {} |
| 138 | explicit Register(uint32_t code) |
| 139 | : CPURegister(kRRegister, code % kNumberOfRegisters, kRegSizeInBits) { |
| 140 | VIXL_ASSERT(GetCode() < kNumberOfRegisters); |
| 141 | } |
| 142 | bool Is(Register ref) const { return GetCode() == ref.GetCode(); } |
| 143 | bool IsLow() const { return GetCode() < kNumberOfT32LowRegisters; } |
| 144 | bool IsLR() const { return GetCode() == kLrCode; } |
| 145 | bool IsPC() const { return GetCode() == kPcCode; } |
| 146 | bool IsSP() const { return GetCode() == kSpCode; } |
| 147 | }; |
| 148 | |
| 149 | std::ostream& operator<<(std::ostream& os, const Register reg); |
| 150 | |
Vincent Belliard | adbb4a7 | 2016-11-22 14:24:54 -0800 | [diff] [blame] | 151 | class RegisterOrAPSR_nzcv { |
| 152 | uint32_t code_; |
| 153 | |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 154 | public: |
Vincent Belliard | adbb4a7 | 2016-11-22 14:24:54 -0800 | [diff] [blame] | 155 | explicit RegisterOrAPSR_nzcv(uint32_t code) : code_(code) { |
| 156 | VIXL_ASSERT(code_ < kNumberOfRegisters); |
| 157 | } |
| 158 | bool IsAPSR_nzcv() const { return code_ == kPcCode; } |
| 159 | uint32_t GetCode() const { return code_; } |
| 160 | Register AsRegister() const { |
| 161 | VIXL_ASSERT(!IsAPSR_nzcv()); |
| 162 | return Register(code_); |
| 163 | } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 164 | }; |
| 165 | |
Vincent Belliard | 5d85018 | 2017-09-25 13:04:30 -0700 | [diff] [blame] | 166 | const RegisterOrAPSR_nzcv APSR_nzcv(kPcCode); |
| 167 | |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 168 | inline std::ostream& operator<<(std::ostream& os, |
| 169 | const RegisterOrAPSR_nzcv reg) { |
Vincent Belliard | adbb4a7 | 2016-11-22 14:24:54 -0800 | [diff] [blame] | 170 | if (reg.IsAPSR_nzcv()) return os << "APSR_nzcv"; |
| 171 | return os << reg.AsRegister(); |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | class SRegister; |
| 175 | class DRegister; |
| 176 | class QRegister; |
| 177 | |
| 178 | class VRegister : public CPURegister { |
| 179 | public: |
| 180 | VRegister() : CPURegister(kNoRegister, 0, 0) {} |
| 181 | VRegister(RegisterType type, uint32_t code, int size) |
| 182 | : CPURegister(type, code, size) {} |
| 183 | |
| 184 | SRegister S() const; |
| 185 | DRegister D() const; |
| 186 | QRegister Q() const; |
| 187 | }; |
| 188 | |
| 189 | class SRegister : public VRegister { |
| 190 | public: |
| 191 | SRegister() : VRegister(kNoRegister, 0, kSRegSizeInBits) {} |
| 192 | explicit SRegister(uint32_t code) |
| 193 | : VRegister(kSRegister, code, kSRegSizeInBits) {} |
| 194 | uint32_t Encode(int single_bit_field, int four_bit_field_lowest_bit) const { |
| 195 | if (four_bit_field_lowest_bit == 0) { |
| 196 | return ((GetCode() & 0x1) << single_bit_field) | |
| 197 | ((GetCode() & 0x1e) >> 1); |
| 198 | } |
| 199 | return ((GetCode() & 0x1) << single_bit_field) | |
| 200 | ((GetCode() & 0x1e) << (four_bit_field_lowest_bit - 1)); |
| 201 | } |
| 202 | }; |
| 203 | |
| 204 | inline unsigned ExtractSRegister(uint32_t instr, |
| 205 | int single_bit_field, |
| 206 | int four_bit_field_lowest_bit) { |
| 207 | VIXL_ASSERT(single_bit_field > 0); |
| 208 | if (four_bit_field_lowest_bit == 0) { |
| 209 | return ((instr << 1) & 0x1e) | ((instr >> single_bit_field) & 0x1); |
| 210 | } |
| 211 | return ((instr >> (four_bit_field_lowest_bit - 1)) & 0x1e) | |
| 212 | ((instr >> single_bit_field) & 0x1); |
| 213 | } |
| 214 | |
| 215 | inline std::ostream& operator<<(std::ostream& os, const SRegister reg) { |
| 216 | return os << "s" << reg.GetCode(); |
| 217 | } |
| 218 | |
| 219 | class DRegister : public VRegister { |
| 220 | public: |
| 221 | DRegister() : VRegister(kNoRegister, 0, kDRegSizeInBits) {} |
| 222 | explicit DRegister(uint32_t code) |
| 223 | : VRegister(kDRegister, code, kDRegSizeInBits) {} |
Vincent Belliard | 97a5640 | 2016-07-13 14:03:32 -0700 | [diff] [blame] | 224 | SRegister GetLane(uint32_t lane) const { |
| 225 | uint32_t lane_count = kDRegSizeInBits / kSRegSizeInBits; |
| 226 | VIXL_ASSERT(lane < lane_count); |
| 227 | VIXL_ASSERT(GetCode() * lane_count < kNumberOfSRegisters); |
| 228 | return SRegister(GetCode() * lane_count + lane); |
| 229 | } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 230 | uint32_t Encode(int single_bit_field, int four_bit_field_lowest_bit) const { |
| 231 | VIXL_ASSERT(single_bit_field >= 4); |
| 232 | return ((GetCode() & 0x10) << (single_bit_field - 4)) | |
| 233 | ((GetCode() & 0xf) << four_bit_field_lowest_bit); |
| 234 | } |
| 235 | }; |
| 236 | |
| 237 | inline unsigned ExtractDRegister(uint32_t instr, |
| 238 | int single_bit_field, |
| 239 | int four_bit_field_lowest_bit) { |
| 240 | VIXL_ASSERT(single_bit_field >= 4); |
| 241 | return ((instr >> (single_bit_field - 4)) & 0x10) | |
| 242 | ((instr >> four_bit_field_lowest_bit) & 0xf); |
| 243 | } |
| 244 | |
| 245 | inline std::ostream& operator<<(std::ostream& os, const DRegister reg) { |
| 246 | return os << "d" << reg.GetCode(); |
| 247 | } |
| 248 | |
| 249 | enum DataTypeType { |
| 250 | kDataTypeS = 0x100, |
| 251 | kDataTypeU = 0x200, |
| 252 | kDataTypeF = 0x300, |
| 253 | kDataTypeI = 0x400, |
| 254 | kDataTypeP = 0x500, |
| 255 | kDataTypeUntyped = 0x600 |
| 256 | }; |
| 257 | const int kDataTypeSizeMask = 0x0ff; |
| 258 | const int kDataTypeTypeMask = 0x100; |
| 259 | enum DataTypeValue { |
| 260 | kDataTypeValueInvalid = 0x000, |
| 261 | kDataTypeValueNone = 0x001, // value used when dt is ignored. |
| 262 | S8 = kDataTypeS | 8, |
| 263 | S16 = kDataTypeS | 16, |
| 264 | S32 = kDataTypeS | 32, |
| 265 | S64 = kDataTypeS | 64, |
| 266 | U8 = kDataTypeU | 8, |
| 267 | U16 = kDataTypeU | 16, |
| 268 | U32 = kDataTypeU | 32, |
| 269 | U64 = kDataTypeU | 64, |
| 270 | F16 = kDataTypeF | 16, |
| 271 | F32 = kDataTypeF | 32, |
| 272 | F64 = kDataTypeF | 64, |
| 273 | I8 = kDataTypeI | 8, |
| 274 | I16 = kDataTypeI | 16, |
| 275 | I32 = kDataTypeI | 32, |
| 276 | I64 = kDataTypeI | 64, |
| 277 | P8 = kDataTypeP | 8, |
| 278 | P64 = kDataTypeP | 64, |
| 279 | Untyped8 = kDataTypeUntyped | 8, |
| 280 | Untyped16 = kDataTypeUntyped | 16, |
| 281 | Untyped32 = kDataTypeUntyped | 32, |
| 282 | Untyped64 = kDataTypeUntyped | 64 |
| 283 | }; |
| 284 | |
| 285 | class DataType { |
| 286 | DataTypeValue value_; |
| 287 | |
| 288 | public: |
Pierre Langlois | 0cec43d | 2017-01-19 17:19:44 +0000 | [diff] [blame] | 289 | explicit DataType(uint32_t size) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 290 | : value_(static_cast<DataTypeValue>(kDataTypeUntyped | size)) { |
| 291 | VIXL_ASSERT((size == 8) || (size == 16) || (size == 32) || (size == 64)); |
| 292 | } |
Pierre Langlois | 0cec43d | 2017-01-19 17:19:44 +0000 | [diff] [blame] | 293 | // Users should be able to use "S8", "S6" and so forth to instantiate this |
| 294 | // class. |
| 295 | DataType(DataTypeValue value) : value_(value) {} // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 296 | DataTypeValue GetValue() const { return value_; } |
| 297 | DataTypeType GetType() const { |
| 298 | return static_cast<DataTypeType>(value_ & kDataTypeTypeMask); |
| 299 | } |
| 300 | uint32_t GetSize() const { return value_ & kDataTypeSizeMask; } |
| 301 | bool IsSize(uint32_t size) const { |
| 302 | return (value_ & kDataTypeSizeMask) == size; |
| 303 | } |
| 304 | const char* GetName() const; |
Vincent Belliard | 8be27ed | 2017-08-16 08:25:47 -0700 | [diff] [blame] | 305 | bool Is(DataType type) const { return value_ == type.value_; } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 306 | bool Is(DataTypeValue value) const { return value_ == value; } |
| 307 | bool Is(DataTypeType type) const { return GetType() == type; } |
| 308 | bool IsNoneOr(DataTypeValue value) const { |
| 309 | return (value_ == value) || (value_ == kDataTypeValueNone); |
| 310 | } |
| 311 | bool Is(DataTypeType type, uint32_t size) const { |
| 312 | return value_ == static_cast<DataTypeValue>(type | size); |
| 313 | } |
| 314 | bool IsNoneOr(DataTypeType type, uint32_t size) const { |
| 315 | return Is(type, size) || Is(kDataTypeValueNone); |
| 316 | } |
| 317 | }; |
| 318 | |
| 319 | inline std::ostream& operator<<(std::ostream& os, DataType dt) { |
| 320 | return os << dt.GetName(); |
| 321 | } |
| 322 | |
| 323 | class DRegisterLane : public DRegister { |
| 324 | uint32_t lane_; |
| 325 | |
| 326 | public: |
| 327 | DRegisterLane(DRegister reg, uint32_t lane) |
| 328 | : DRegister(reg.GetCode()), lane_(lane) {} |
| 329 | DRegisterLane(uint32_t code, uint32_t lane) : DRegister(code), lane_(lane) {} |
| 330 | uint32_t GetLane() const { return lane_; } |
| 331 | uint32_t EncodeX(DataType dt, |
| 332 | int single_bit_field, |
| 333 | int four_bit_field_lowest_bit) const { |
| 334 | VIXL_ASSERT(single_bit_field >= 4); |
| 335 | uint32_t value = lane_ << ((dt.GetSize() == 16) ? 3 : 4) | GetCode(); |
| 336 | return ((value & 0x10) << (single_bit_field - 4)) | |
| 337 | ((value & 0xf) << four_bit_field_lowest_bit); |
| 338 | } |
| 339 | }; |
| 340 | |
| 341 | inline unsigned ExtractDRegisterAndLane(uint32_t instr, |
| 342 | DataType dt, |
| 343 | int single_bit_field, |
| 344 | int four_bit_field_lowest_bit, |
| 345 | int* lane) { |
| 346 | VIXL_ASSERT(single_bit_field >= 4); |
| 347 | uint32_t value = ((instr >> (single_bit_field - 4)) & 0x10) | |
| 348 | ((instr >> four_bit_field_lowest_bit) & 0xf); |
| 349 | if (dt.GetSize() == 16) { |
| 350 | *lane = value >> 3; |
| 351 | return value & 0x7; |
| 352 | } |
| 353 | *lane = value >> 4; |
| 354 | return value & 0xf; |
| 355 | } |
| 356 | |
| 357 | inline std::ostream& operator<<(std::ostream& os, const DRegisterLane lane) { |
| 358 | os << "d" << lane.GetCode() << "["; |
| 359 | if (lane.GetLane() == static_cast<uint32_t>(-1)) return os << "??]"; |
| 360 | return os << lane.GetLane() << "]"; |
| 361 | } |
| 362 | |
| 363 | class QRegister : public VRegister { |
| 364 | public: |
| 365 | QRegister() : VRegister(kNoRegister, 0, kQRegSizeInBits) {} |
| 366 | explicit QRegister(uint32_t code) |
| 367 | : VRegister(kQRegister, code, kQRegSizeInBits) {} |
| 368 | uint32_t Encode(int offset) { return GetCode() << offset; } |
Vincent Belliard | 97a5640 | 2016-07-13 14:03:32 -0700 | [diff] [blame] | 369 | DRegister GetDLane(uint32_t lane) const { |
| 370 | uint32_t lane_count = kQRegSizeInBits / kDRegSizeInBits; |
| 371 | VIXL_ASSERT(lane < lane_count); |
| 372 | return DRegister(GetCode() * lane_count + lane); |
| 373 | } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 374 | DRegister GetLowDRegister() const { return DRegister(GetCode() * 2); } |
| 375 | DRegister GetHighDRegister() const { return DRegister(1 + GetCode() * 2); } |
Vincent Belliard | 97a5640 | 2016-07-13 14:03:32 -0700 | [diff] [blame] | 376 | SRegister GetSLane(uint32_t lane) const { |
| 377 | uint32_t lane_count = kQRegSizeInBits / kSRegSizeInBits; |
| 378 | VIXL_ASSERT(lane < lane_count); |
| 379 | VIXL_ASSERT(GetCode() * lane_count < kNumberOfSRegisters); |
| 380 | return SRegister(GetCode() * lane_count + lane); |
| 381 | } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 382 | uint32_t Encode(int single_bit_field, int four_bit_field_lowest_bit) { |
| 383 | // Encode "code * 2". |
| 384 | VIXL_ASSERT(single_bit_field >= 3); |
| 385 | return ((GetCode() & 0x8) << (single_bit_field - 3)) | |
| 386 | ((GetCode() & 0x7) << (four_bit_field_lowest_bit + 1)); |
| 387 | } |
| 388 | }; |
| 389 | |
| 390 | inline unsigned ExtractQRegister(uint32_t instr, |
| 391 | int single_bit_field, |
| 392 | int four_bit_field_lowest_bit) { |
| 393 | VIXL_ASSERT(single_bit_field >= 3); |
| 394 | return ((instr >> (single_bit_field - 3)) & 0x8) | |
| 395 | ((instr >> (four_bit_field_lowest_bit + 1)) & 0x7); |
| 396 | } |
| 397 | |
| 398 | inline std::ostream& operator<<(std::ostream& os, const QRegister reg) { |
| 399 | return os << "q" << reg.GetCode(); |
| 400 | } |
| 401 | |
| 402 | // clang-format off |
Alexandre Rames | 1107e04 | 2016-09-20 10:30:40 +0100 | [diff] [blame] | 403 | #define AARCH32_REGISTER_CODE_LIST(R) \ |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 404 | R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ |
| 405 | R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) |
| 406 | // clang-format on |
| 407 | #define DEFINE_REGISTER(N) const Register r##N(N); |
Alexandre Rames | 1107e04 | 2016-09-20 10:30:40 +0100 | [diff] [blame] | 408 | AARCH32_REGISTER_CODE_LIST(DEFINE_REGISTER) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 409 | #undef DEFINE_REGISTER |
Alexandre Rames | 1107e04 | 2016-09-20 10:30:40 +0100 | [diff] [blame] | 410 | #undef AARCH32_REGISTER_CODE_LIST |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 411 | |
| 412 | enum RegNum { kIPRegNum = 12, kSPRegNum = 13, kLRRegNum = 14, kPCRegNum = 15 }; |
| 413 | |
| 414 | const Register ip(kIPRegNum); |
| 415 | const Register sp(kSPRegNum); |
| 416 | const Register pc(kPCRegNum); |
| 417 | const Register lr(kLRRegNum); |
| 418 | const Register NoReg; |
| 419 | const VRegister NoVReg; |
| 420 | |
| 421 | // clang-format off |
| 422 | #define SREGISTER_CODE_LIST(R) \ |
| 423 | R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ |
| 424 | R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ |
| 425 | R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ |
| 426 | R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) |
| 427 | // clang-format on |
| 428 | #define DEFINE_REGISTER(N) const SRegister s##N(N); |
| 429 | SREGISTER_CODE_LIST(DEFINE_REGISTER) |
| 430 | #undef DEFINE_REGISTER |
| 431 | #undef SREGISTER_CODE_LIST |
| 432 | const SRegister NoSReg; |
| 433 | |
| 434 | // clang-format off |
| 435 | #define DREGISTER_CODE_LIST(R) \ |
| 436 | R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ |
| 437 | R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ |
| 438 | R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ |
| 439 | R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) |
| 440 | // clang-format on |
| 441 | #define DEFINE_REGISTER(N) const DRegister d##N(N); |
| 442 | DREGISTER_CODE_LIST(DEFINE_REGISTER) |
| 443 | #undef DEFINE_REGISTER |
| 444 | #undef DREGISTER_CODE_LIST |
| 445 | const DRegister NoDReg; |
| 446 | |
| 447 | // clang-format off |
| 448 | #define QREGISTER_CODE_LIST(R) \ |
| 449 | R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ |
| 450 | R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) |
| 451 | // clang-format on |
| 452 | #define DEFINE_REGISTER(N) const QRegister q##N(N); |
| 453 | QREGISTER_CODE_LIST(DEFINE_REGISTER) |
| 454 | #undef DEFINE_REGISTER |
| 455 | #undef QREGISTER_CODE_LIST |
| 456 | const QRegister NoQReg; |
| 457 | |
| 458 | class RegisterList { |
| 459 | public: |
| 460 | RegisterList() : list_(0) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 461 | RegisterList(Register reg) // NOLINT(runtime/explicit) |
| 462 | : list_(RegisterToList(reg)) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 463 | RegisterList(Register reg1, Register reg2) |
| 464 | : list_(RegisterToList(reg1) | RegisterToList(reg2)) {} |
| 465 | RegisterList(Register reg1, Register reg2, Register reg3) |
| 466 | : list_(RegisterToList(reg1) | RegisterToList(reg2) | |
| 467 | RegisterToList(reg3)) {} |
| 468 | RegisterList(Register reg1, Register reg2, Register reg3, Register reg4) |
| 469 | : list_(RegisterToList(reg1) | RegisterToList(reg2) | |
| 470 | RegisterToList(reg3) | RegisterToList(reg4)) {} |
| 471 | explicit RegisterList(uint32_t list) : list_(list) {} |
| 472 | uint32_t GetList() const { return list_; } |
| 473 | void SetList(uint32_t list) { list_ = list; } |
| 474 | bool Includes(const Register& reg) const { |
| 475 | return (list_ & RegisterToList(reg)) != 0; |
| 476 | } |
| 477 | void Combine(const RegisterList& other) { list_ |= other.GetList(); } |
| 478 | void Combine(const Register& reg) { list_ |= RegisterToList(reg); } |
| 479 | void Remove(const RegisterList& other) { list_ &= ~other.GetList(); } |
| 480 | void Remove(const Register& reg) { list_ &= ~RegisterToList(reg); } |
| 481 | bool Overlaps(const RegisterList& other) const { |
| 482 | return (list_ & other.list_) != 0; |
| 483 | } |
| 484 | bool IsR0toR7orPC() const { |
| 485 | // True if all the registers from the list are not from r8-r14. |
| 486 | return (list_ & 0x7f00) == 0; |
| 487 | } |
| 488 | bool IsR0toR7orLR() const { |
| 489 | // True if all the registers from the list are not from r8-r13 nor from r15. |
| 490 | return (list_ & 0xbf00) == 0; |
| 491 | } |
| 492 | Register GetFirstAvailableRegister() const; |
| 493 | bool IsEmpty() const { return list_ == 0; } |
Jacob Bramley | 82f4960 | 2021-02-03 11:57:43 +0000 | [diff] [blame] | 494 | bool IsSingleRegister() const { return IsPowerOf2(list_); } |
Jacob Bramley | 5dc3c76 | 2021-02-08 14:39:30 +0000 | [diff] [blame] | 495 | int GetCount() const { return CountSetBits(list_); } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 496 | static RegisterList Union(const RegisterList& list_1, |
| 497 | const RegisterList& list_2) { |
| 498 | return RegisterList(list_1.list_ | list_2.list_); |
| 499 | } |
| 500 | static RegisterList Union(const RegisterList& list_1, |
| 501 | const RegisterList& list_2, |
| 502 | const RegisterList& list_3) { |
| 503 | return Union(list_1, Union(list_2, list_3)); |
| 504 | } |
| 505 | static RegisterList Union(const RegisterList& list_1, |
| 506 | const RegisterList& list_2, |
| 507 | const RegisterList& list_3, |
| 508 | const RegisterList& list_4) { |
| 509 | return Union(Union(list_1, list_2), Union(list_3, list_4)); |
| 510 | } |
| 511 | static RegisterList Intersection(const RegisterList& list_1, |
| 512 | const RegisterList& list_2) { |
| 513 | return RegisterList(list_1.list_ & list_2.list_); |
| 514 | } |
| 515 | static RegisterList Intersection(const RegisterList& list_1, |
| 516 | const RegisterList& list_2, |
| 517 | const RegisterList& list_3) { |
| 518 | return Intersection(list_1, Intersection(list_2, list_3)); |
| 519 | } |
| 520 | static RegisterList Intersection(const RegisterList& list_1, |
| 521 | const RegisterList& list_2, |
| 522 | const RegisterList& list_3, |
| 523 | const RegisterList& list_4) { |
| 524 | return Intersection(Intersection(list_1, list_2), |
| 525 | Intersection(list_3, list_4)); |
| 526 | } |
| 527 | |
| 528 | private: |
| 529 | static uint32_t RegisterToList(Register reg) { |
| 530 | if (reg.GetType() == CPURegister::kNoRegister) { |
| 531 | return 0; |
| 532 | } else { |
| 533 | return UINT32_C(1) << reg.GetCode(); |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | // Bitfield representation of all registers in the list |
| 538 | // (1 for r0, 2 for r1, 4 for r2, ...). |
| 539 | uint32_t list_; |
| 540 | }; |
| 541 | |
| 542 | inline uint32_t GetRegisterListEncoding(const RegisterList& registers, |
| 543 | int first, |
| 544 | int count) { |
| 545 | return (registers.GetList() >> first) & ((1 << count) - 1); |
| 546 | } |
| 547 | |
| 548 | std::ostream& operator<<(std::ostream& os, RegisterList registers); |
| 549 | |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 550 | class VRegisterList { |
| 551 | public: |
| 552 | VRegisterList() : list_(0) {} |
| 553 | explicit VRegisterList(VRegister reg) : list_(RegisterToList(reg)) {} |
| 554 | VRegisterList(VRegister reg1, VRegister reg2) |
| 555 | : list_(RegisterToList(reg1) | RegisterToList(reg2)) {} |
| 556 | VRegisterList(VRegister reg1, VRegister reg2, VRegister reg3) |
| 557 | : list_(RegisterToList(reg1) | RegisterToList(reg2) | |
| 558 | RegisterToList(reg3)) {} |
| 559 | VRegisterList(VRegister reg1, VRegister reg2, VRegister reg3, VRegister reg4) |
| 560 | : list_(RegisterToList(reg1) | RegisterToList(reg2) | |
| 561 | RegisterToList(reg3) | RegisterToList(reg4)) {} |
| 562 | explicit VRegisterList(uint64_t list) : list_(list) {} |
| 563 | uint64_t GetList() const { return list_; } |
| 564 | void SetList(uint64_t list) { list_ = list; } |
Jacob Bramley | e6c6319 | 2016-11-16 13:47:23 +0000 | [diff] [blame] | 565 | // Because differently-sized V registers overlap with one another, there is no |
| 566 | // way to implement a single 'Includes' function in a way that is unsurprising |
| 567 | // for all existing uses. |
| 568 | bool IncludesAllOf(const VRegister& reg) const { |
| 569 | return (list_ & RegisterToList(reg)) == RegisterToList(reg); |
| 570 | } |
| 571 | bool IncludesAliasOf(const VRegister& reg) const { |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 572 | return (list_ & RegisterToList(reg)) != 0; |
| 573 | } |
| 574 | void Combine(const VRegisterList& other) { list_ |= other.GetList(); } |
| 575 | void Combine(const VRegister& reg) { list_ |= RegisterToList(reg); } |
| 576 | void Remove(const VRegisterList& other) { list_ &= ~other.GetList(); } |
| 577 | void Remove(const VRegister& reg) { list_ &= ~RegisterToList(reg); } |
| 578 | bool Overlaps(const VRegisterList& other) const { |
| 579 | return (list_ & other.list_) != 0; |
| 580 | } |
| 581 | QRegister GetFirstAvailableQRegister() const; |
| 582 | DRegister GetFirstAvailableDRegister() const; |
| 583 | SRegister GetFirstAvailableSRegister() const; |
| 584 | bool IsEmpty() const { return list_ == 0; } |
| 585 | static VRegisterList Union(const VRegisterList& list_1, |
| 586 | const VRegisterList& list_2) { |
| 587 | return VRegisterList(list_1.list_ | list_2.list_); |
| 588 | } |
| 589 | static VRegisterList Union(const VRegisterList& list_1, |
| 590 | const VRegisterList& list_2, |
| 591 | const VRegisterList& list_3) { |
| 592 | return Union(list_1, Union(list_2, list_3)); |
| 593 | } |
| 594 | static VRegisterList Union(const VRegisterList& list_1, |
| 595 | const VRegisterList& list_2, |
| 596 | const VRegisterList& list_3, |
| 597 | const VRegisterList& list_4) { |
| 598 | return Union(Union(list_1, list_2), Union(list_3, list_4)); |
| 599 | } |
| 600 | static VRegisterList Intersection(const VRegisterList& list_1, |
| 601 | const VRegisterList& list_2) { |
| 602 | return VRegisterList(list_1.list_ & list_2.list_); |
| 603 | } |
| 604 | static VRegisterList Intersection(const VRegisterList& list_1, |
| 605 | const VRegisterList& list_2, |
| 606 | const VRegisterList& list_3) { |
| 607 | return Intersection(list_1, Intersection(list_2, list_3)); |
| 608 | } |
| 609 | static VRegisterList Intersection(const VRegisterList& list_1, |
| 610 | const VRegisterList& list_2, |
| 611 | const VRegisterList& list_3, |
| 612 | const VRegisterList& list_4) { |
| 613 | return Intersection(Intersection(list_1, list_2), |
| 614 | Intersection(list_3, list_4)); |
| 615 | } |
| 616 | |
| 617 | private: |
| 618 | static uint64_t RegisterToList(VRegister reg) { |
| 619 | if (reg.GetType() == CPURegister::kNoRegister) { |
| 620 | return 0; |
| 621 | } else { |
| 622 | switch (reg.GetSizeInBits()) { |
| 623 | case kQRegSizeInBits: |
| 624 | return UINT64_C(0xf) << (reg.GetCode() * 4); |
| 625 | case kDRegSizeInBits: |
| 626 | return UINT64_C(0x3) << (reg.GetCode() * 2); |
| 627 | case kSRegSizeInBits: |
| 628 | return UINT64_C(0x1) << reg.GetCode(); |
| 629 | default: |
| 630 | VIXL_UNREACHABLE(); |
| 631 | return 0; |
| 632 | } |
| 633 | } |
| 634 | } |
| 635 | |
| 636 | // Bitfield representation of all registers in the list. |
| 637 | // (0x3 for d0, 0xc0 for d1, 0x30 for d2, ...). We have one, two or four bits |
| 638 | // per register according to their size. This way we can make sure that we |
Jacob Bramley | e6c6319 | 2016-11-16 13:47:23 +0000 | [diff] [blame] | 639 | // account for overlapping registers. |
| 640 | // A register is wholly included in this list only if all of its bits are set. |
| 641 | // A register is aliased by the list if at least one of its bits are set. |
| 642 | // The IncludesAllOf and IncludesAliasOf helpers are provided to make this |
| 643 | // distinction clear. |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 644 | uint64_t list_; |
| 645 | }; |
| 646 | |
| 647 | class SRegisterList { |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 648 | SRegister first_; |
| 649 | int length_; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 650 | |
| 651 | public: |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 652 | explicit SRegisterList(SRegister reg) : first_(reg.GetCode()), length_(1) {} |
| 653 | SRegisterList(SRegister first, int length) |
| 654 | : first_(first.GetCode()), length_(length) { |
| 655 | VIXL_ASSERT(length >= 0); |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 656 | } |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 657 | SRegister GetSRegister(int n) const { |
| 658 | VIXL_ASSERT(n >= 0); |
| 659 | VIXL_ASSERT(n < length_); |
| 660 | return SRegister((first_.GetCode() + n) % kNumberOfSRegisters); |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 661 | } |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 662 | const SRegister& GetFirstSRegister() const { return first_; } |
| 663 | SRegister GetLastSRegister() const { return GetSRegister(length_ - 1); } |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 664 | int GetLength() const { return length_; } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 665 | }; |
| 666 | |
| 667 | std::ostream& operator<<(std::ostream& os, SRegisterList registers); |
| 668 | |
| 669 | class DRegisterList { |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 670 | DRegister first_; |
| 671 | int length_; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 672 | |
| 673 | public: |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 674 | explicit DRegisterList(DRegister reg) : first_(reg.GetCode()), length_(1) {} |
| 675 | DRegisterList(DRegister first, int length) |
| 676 | : first_(first.GetCode()), length_(length) { |
| 677 | VIXL_ASSERT(length >= 0); |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 678 | } |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 679 | DRegister GetDRegister(int n) const { |
| 680 | VIXL_ASSERT(n >= 0); |
| 681 | VIXL_ASSERT(n < length_); |
| 682 | return DRegister((first_.GetCode() + n) % kMaxNumberOfDRegisters); |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 683 | } |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 684 | const DRegister& GetFirstDRegister() const { return first_; } |
| 685 | DRegister GetLastDRegister() const { return GetDRegister(length_ - 1); } |
Pierre Langlois | 71bca30 | 2016-08-23 14:45:02 +0100 | [diff] [blame] | 686 | int GetLength() const { return length_; } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 687 | }; |
| 688 | |
| 689 | std::ostream& operator<<(std::ostream& os, DRegisterList registers); |
| 690 | |
| 691 | enum SpacingType { kSingle, kDouble }; |
| 692 | |
| 693 | enum TransferType { kMultipleLanes, kOneLane, kAllLanes }; |
| 694 | |
| 695 | class NeonRegisterList { |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 696 | DRegister first_; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 697 | SpacingType spacing_; |
| 698 | TransferType type_; |
| 699 | int lane_; |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 700 | int length_; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 701 | |
| 702 | public: |
| 703 | NeonRegisterList(DRegister reg, TransferType type) |
| 704 | : first_(reg.GetCode()), |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 705 | spacing_(kSingle), |
| 706 | type_(type), |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 707 | lane_(-1), |
| 708 | length_(1) { |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 709 | VIXL_ASSERT(type_ != kOneLane); |
| 710 | } |
| 711 | NeonRegisterList(DRegister reg, int lane) |
| 712 | : first_(reg.GetCode()), |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 713 | spacing_(kSingle), |
| 714 | type_(kOneLane), |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 715 | lane_(lane), |
| 716 | length_(1) { |
Vincent Belliard | 36fb1ce | 2017-10-06 07:38:27 -0700 | [diff] [blame] | 717 | VIXL_ASSERT((lane_ >= 0) && (lane_ < 8)); |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 718 | } |
| 719 | NeonRegisterList(DRegister first, |
| 720 | DRegister last, |
| 721 | SpacingType spacing, |
| 722 | TransferType type) |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 723 | : first_(first.GetCode()), spacing_(spacing), type_(type), lane_(-1) { |
| 724 | VIXL_ASSERT(type != kOneLane); |
| 725 | VIXL_ASSERT(first.GetCode() <= last.GetCode()); |
| 726 | |
| 727 | int range = last.GetCode() - first.GetCode(); |
| 728 | VIXL_ASSERT(IsSingleSpaced() || IsMultiple(range, 2)); |
| 729 | length_ = (IsDoubleSpaced() ? (range / 2) : range) + 1; |
| 730 | |
| 731 | VIXL_ASSERT(length_ <= 4); |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 732 | } |
| 733 | NeonRegisterList(DRegister first, |
| 734 | DRegister last, |
| 735 | SpacingType spacing, |
| 736 | int lane) |
| 737 | : first_(first.GetCode()), |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 738 | spacing_(spacing), |
| 739 | type_(kOneLane), |
| 740 | lane_(lane) { |
Vincent Belliard | 36fb1ce | 2017-10-06 07:38:27 -0700 | [diff] [blame] | 741 | VIXL_ASSERT((lane >= 0) && (lane < 8)); |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 742 | VIXL_ASSERT(first.GetCode() <= last.GetCode()); |
| 743 | |
| 744 | int range = last.GetCode() - first.GetCode(); |
| 745 | VIXL_ASSERT(IsSingleSpaced() || IsMultiple(range, 2)); |
| 746 | length_ = (IsDoubleSpaced() ? (range / 2) : range) + 1; |
| 747 | |
| 748 | VIXL_ASSERT(length_ <= 4); |
| 749 | } |
| 750 | DRegister GetDRegister(int n) const { |
| 751 | VIXL_ASSERT(n >= 0); |
| 752 | VIXL_ASSERT(n < length_); |
| 753 | unsigned code = first_.GetCode() + (IsDoubleSpaced() ? (2 * n) : n); |
| 754 | VIXL_ASSERT(code < kMaxNumberOfDRegisters); |
| 755 | return DRegister(code); |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 756 | } |
| 757 | const DRegister& GetFirstDRegister() const { return first_; } |
Jacob Bramley | 29f71f9 | 2016-11-16 16:47:57 +0000 | [diff] [blame] | 758 | DRegister GetLastDRegister() const { return GetDRegister(length_ - 1); } |
| 759 | int GetLength() const { return length_; } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 760 | bool IsSingleSpaced() const { return spacing_ == kSingle; } |
| 761 | bool IsDoubleSpaced() const { return spacing_ == kDouble; } |
| 762 | bool IsTransferAllLanes() const { return type_ == kAllLanes; } |
| 763 | bool IsTransferOneLane() const { return type_ == kOneLane; } |
| 764 | bool IsTransferMultipleLanes() const { return type_ == kMultipleLanes; } |
| 765 | int GetTransferLane() const { return lane_; } |
| 766 | }; |
| 767 | |
| 768 | std::ostream& operator<<(std::ostream& os, NeonRegisterList registers); |
| 769 | |
| 770 | enum SpecialRegisterType { APSR = 0, CPSR = 0, SPSR = 1 }; |
| 771 | |
| 772 | class SpecialRegister { |
| 773 | uint32_t reg_; |
| 774 | |
| 775 | public: |
| 776 | explicit SpecialRegister(uint32_t reg) : reg_(reg) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 777 | SpecialRegister(SpecialRegisterType reg) // NOLINT(runtime/explicit) |
| 778 | : reg_(reg) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 779 | uint32_t GetReg() const { return reg_; } |
| 780 | const char* GetName() const; |
| 781 | bool Is(SpecialRegister value) const { return reg_ == value.reg_; } |
| 782 | bool Is(uint32_t value) const { return reg_ == value; } |
| 783 | bool IsNot(uint32_t value) const { return reg_ != value; } |
| 784 | }; |
| 785 | |
| 786 | inline std::ostream& operator<<(std::ostream& os, SpecialRegister reg) { |
| 787 | return os << reg.GetName(); |
| 788 | } |
| 789 | |
| 790 | enum BankedRegisterType { |
| 791 | R8_usr = 0x00, |
| 792 | R9_usr = 0x01, |
| 793 | R10_usr = 0x02, |
| 794 | R11_usr = 0x03, |
| 795 | R12_usr = 0x04, |
| 796 | SP_usr = 0x05, |
| 797 | LR_usr = 0x06, |
| 798 | R8_fiq = 0x08, |
| 799 | R9_fiq = 0x09, |
| 800 | R10_fiq = 0x0a, |
| 801 | R11_fiq = 0x0b, |
| 802 | R12_fiq = 0x0c, |
| 803 | SP_fiq = 0x0d, |
| 804 | LR_fiq = 0x0e, |
| 805 | LR_irq = 0x10, |
| 806 | SP_irq = 0x11, |
| 807 | LR_svc = 0x12, |
| 808 | SP_svc = 0x13, |
| 809 | LR_abt = 0x14, |
| 810 | SP_abt = 0x15, |
| 811 | LR_und = 0x16, |
| 812 | SP_und = 0x17, |
| 813 | LR_mon = 0x1c, |
| 814 | SP_mon = 0x1d, |
| 815 | ELR_hyp = 0x1e, |
| 816 | SP_hyp = 0x1f, |
| 817 | SPSR_fiq = 0x2e, |
| 818 | SPSR_irq = 0x30, |
| 819 | SPSR_svc = 0x32, |
| 820 | SPSR_abt = 0x34, |
| 821 | SPSR_und = 0x36, |
| 822 | SPSR_mon = 0x3c, |
| 823 | SPSR_hyp = 0x3e |
| 824 | }; |
| 825 | |
| 826 | class BankedRegister { |
| 827 | uint32_t reg_; |
| 828 | |
| 829 | public: |
| 830 | explicit BankedRegister(unsigned reg) : reg_(reg) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 831 | BankedRegister(BankedRegisterType reg) // NOLINT(runtime/explicit) |
| 832 | : reg_(reg) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 833 | uint32_t GetCode() const { return reg_; } |
| 834 | const char* GetName() const; |
| 835 | }; |
| 836 | |
| 837 | inline std::ostream& operator<<(std::ostream& os, BankedRegister reg) { |
| 838 | return os << reg.GetName(); |
| 839 | } |
| 840 | |
| 841 | enum MaskedSpecialRegisterType { |
| 842 | APSR_nzcvq = 0x08, |
| 843 | APSR_g = 0x04, |
| 844 | APSR_nzcvqg = 0x0c, |
| 845 | CPSR_c = 0x01, |
| 846 | CPSR_x = 0x02, |
| 847 | CPSR_xc = 0x03, |
| 848 | CPSR_s = APSR_g, |
| 849 | CPSR_sc = 0x05, |
| 850 | CPSR_sx = 0x06, |
| 851 | CPSR_sxc = 0x07, |
| 852 | CPSR_f = APSR_nzcvq, |
| 853 | CPSR_fc = 0x09, |
| 854 | CPSR_fx = 0x0a, |
| 855 | CPSR_fxc = 0x0b, |
| 856 | CPSR_fs = APSR_nzcvqg, |
| 857 | CPSR_fsc = 0x0d, |
| 858 | CPSR_fsx = 0x0e, |
| 859 | CPSR_fsxc = 0x0f, |
| 860 | SPSR_c = 0x11, |
| 861 | SPSR_x = 0x12, |
| 862 | SPSR_xc = 0x13, |
| 863 | SPSR_s = 0x14, |
| 864 | SPSR_sc = 0x15, |
| 865 | SPSR_sx = 0x16, |
| 866 | SPSR_sxc = 0x17, |
| 867 | SPSR_f = 0x18, |
| 868 | SPSR_fc = 0x19, |
| 869 | SPSR_fx = 0x1a, |
| 870 | SPSR_fxc = 0x1b, |
| 871 | SPSR_fs = 0x1c, |
| 872 | SPSR_fsc = 0x1d, |
| 873 | SPSR_fsx = 0x1e, |
| 874 | SPSR_fsxc = 0x1f |
| 875 | }; |
| 876 | |
| 877 | class MaskedSpecialRegister { |
| 878 | uint32_t reg_; |
| 879 | |
| 880 | public: |
| 881 | explicit MaskedSpecialRegister(uint32_t reg) : reg_(reg) { |
| 882 | VIXL_ASSERT(reg <= SPSR_fsxc); |
| 883 | } |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 884 | MaskedSpecialRegister( |
| 885 | MaskedSpecialRegisterType reg) // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 886 | : reg_(reg) {} |
| 887 | uint32_t GetReg() const { return reg_; } |
| 888 | const char* GetName() const; |
| 889 | bool Is(MaskedSpecialRegister value) const { return reg_ == value.reg_; } |
| 890 | bool Is(uint32_t value) const { return reg_ == value; } |
| 891 | bool IsNot(uint32_t value) const { return reg_ != value; } |
| 892 | }; |
| 893 | |
| 894 | inline std::ostream& operator<<(std::ostream& os, MaskedSpecialRegister reg) { |
| 895 | return os << reg.GetName(); |
| 896 | } |
| 897 | |
| 898 | enum SpecialFPRegisterType { |
| 899 | FPSID = 0x0, |
| 900 | FPSCR = 0x1, |
| 901 | MVFR2 = 0x5, |
| 902 | MVFR1 = 0x6, |
| 903 | MVFR0 = 0x7, |
| 904 | FPEXC = 0x8 |
| 905 | }; |
| 906 | |
| 907 | class SpecialFPRegister { |
| 908 | uint32_t reg_; |
| 909 | |
| 910 | public: |
| 911 | explicit SpecialFPRegister(uint32_t reg) : reg_(reg) { |
| 912 | #ifdef VIXL_DEBUG |
| 913 | switch (reg) { |
| 914 | case FPSID: |
| 915 | case FPSCR: |
| 916 | case MVFR2: |
| 917 | case MVFR1: |
| 918 | case MVFR0: |
| 919 | case FPEXC: |
| 920 | break; |
| 921 | default: |
| 922 | VIXL_UNREACHABLE(); |
| 923 | } |
| 924 | #endif |
| 925 | } |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 926 | SpecialFPRegister(SpecialFPRegisterType reg) // NOLINT(runtime/explicit) |
| 927 | : reg_(reg) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 928 | uint32_t GetReg() const { return reg_; } |
| 929 | const char* GetName() const; |
| 930 | bool Is(SpecialFPRegister value) const { return reg_ == value.reg_; } |
| 931 | bool Is(uint32_t value) const { return reg_ == value; } |
| 932 | bool IsNot(uint32_t value) const { return reg_ != value; } |
| 933 | }; |
| 934 | |
| 935 | inline std::ostream& operator<<(std::ostream& os, SpecialFPRegister reg) { |
| 936 | return os << reg.GetName(); |
| 937 | } |
| 938 | |
| 939 | class CRegister { |
| 940 | uint32_t code_; |
| 941 | |
| 942 | public: |
| 943 | explicit CRegister(uint32_t code) : code_(code) { |
| 944 | VIXL_ASSERT(code < kNumberOfRegisters); |
| 945 | } |
| 946 | uint32_t GetCode() const { return code_; } |
| 947 | bool Is(CRegister value) const { return code_ == value.code_; } |
| 948 | }; |
| 949 | |
| 950 | inline std::ostream& operator<<(std::ostream& os, const CRegister reg) { |
| 951 | return os << "c" << reg.GetCode(); |
| 952 | } |
| 953 | |
| 954 | // clang-format off |
| 955 | #define CREGISTER_CODE_LIST(R) \ |
| 956 | R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ |
| 957 | R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) |
| 958 | // clang-format on |
| 959 | #define DEFINE_CREGISTER(N) const CRegister c##N(N); |
| 960 | CREGISTER_CODE_LIST(DEFINE_CREGISTER) |
| 961 | |
| 962 | enum CoprocessorName { p10 = 10, p11 = 11, p14 = 14, p15 = 15 }; |
| 963 | |
| 964 | class Coprocessor { |
| 965 | uint32_t coproc_; |
| 966 | |
| 967 | public: |
| 968 | explicit Coprocessor(uint32_t coproc) : coproc_(coproc) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 969 | Coprocessor(CoprocessorName coproc) // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 970 | : coproc_(static_cast<uint32_t>(coproc)) {} |
| 971 | bool Is(Coprocessor coproc) const { return coproc_ == coproc.coproc_; } |
| 972 | bool Is(CoprocessorName coproc) const { return coproc_ == coproc; } |
| 973 | uint32_t GetCoprocessor() const { return coproc_; } |
| 974 | }; |
| 975 | |
| 976 | inline std::ostream& operator<<(std::ostream& os, Coprocessor coproc) { |
| 977 | return os << "p" << coproc.GetCoprocessor(); |
| 978 | } |
| 979 | |
| 980 | enum ConditionType { |
| 981 | eq = 0, |
| 982 | ne = 1, |
| 983 | cs = 2, |
| 984 | cc = 3, |
| 985 | mi = 4, |
| 986 | pl = 5, |
| 987 | vs = 6, |
| 988 | vc = 7, |
| 989 | hi = 8, |
| 990 | ls = 9, |
| 991 | ge = 10, |
| 992 | lt = 11, |
| 993 | gt = 12, |
| 994 | le = 13, |
| 995 | al = 14, |
| 996 | hs = cs, |
| 997 | lo = cc |
| 998 | }; |
| 999 | |
| 1000 | class Condition { |
| 1001 | uint32_t condition_; |
| 1002 | static const uint32_t kNever = 15; |
| 1003 | static const uint32_t kMask = 0xf; |
Vincent Belliard | fad3507 | 2016-11-08 12:41:21 -0800 | [diff] [blame] | 1004 | static const uint32_t kNone = 0x10 | al; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1005 | |
| 1006 | public: |
Vincent Belliard | fad3507 | 2016-11-08 12:41:21 -0800 | [diff] [blame] | 1007 | static const Condition None() { return Condition(kNone); } |
Vincent Belliard | 3d39ef9 | 2017-09-20 13:08:11 -0700 | [diff] [blame] | 1008 | static const Condition Never() { return Condition(kNever); } |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1009 | explicit Condition(uint32_t condition) : condition_(condition) { |
| 1010 | VIXL_ASSERT(condition <= kNone); |
| 1011 | } |
Pierre Langlois | 0cec43d | 2017-01-19 17:19:44 +0000 | [diff] [blame] | 1012 | // Users should be able to use "eq", "ne" and so forth to instantiate this |
| 1013 | // class. |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1014 | Condition(ConditionType condition) // NOLINT(runtime/explicit) |
| 1015 | : condition_(condition) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1016 | uint32_t GetCondition() const { return condition_ & kMask; } |
| 1017 | bool IsNone() const { return condition_ == kNone; } |
| 1018 | const char* GetName() const; |
| 1019 | bool Is(Condition value) const { return condition_ == value.condition_; } |
| 1020 | bool Is(uint32_t value) const { return condition_ == value; } |
| 1021 | bool IsNot(uint32_t value) const { return condition_ != value; } |
| 1022 | bool IsNever() const { return condition_ == kNever; } |
| 1023 | bool IsNotNever() const { return condition_ != kNever; } |
| 1024 | Condition Negate() const { |
| 1025 | VIXL_ASSERT(IsNot(al) && IsNot(kNever)); |
| 1026 | return Condition(condition_ ^ 1); |
| 1027 | } |
| 1028 | }; |
| 1029 | |
| 1030 | inline std::ostream& operator<<(std::ostream& os, Condition condition) { |
| 1031 | return os << condition.GetName(); |
| 1032 | } |
| 1033 | |
| 1034 | enum SignType { plus, minus }; |
| 1035 | |
| 1036 | class Sign { |
| 1037 | public: |
| 1038 | Sign() : sign_(plus) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1039 | Sign(SignType sign) : sign_(sign) {} // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1040 | const char* GetName() const { return (IsPlus() ? "" : "-"); } |
| 1041 | bool IsPlus() const { return sign_ == plus; } |
| 1042 | bool IsMinus() const { return sign_ == minus; } |
| 1043 | int32_t ApplyTo(uint32_t value) { return IsPlus() ? value : -value; } |
| 1044 | |
| 1045 | private: |
| 1046 | SignType sign_; |
| 1047 | }; |
| 1048 | |
| 1049 | inline std::ostream& operator<<(std::ostream& os, Sign sign) { |
| 1050 | return os << sign.GetName(); |
| 1051 | } |
| 1052 | |
| 1053 | enum ShiftType { LSL = 0x0, LSR = 0x1, ASR = 0x2, ROR = 0x3, RRX = 0x4 }; |
| 1054 | |
| 1055 | class Shift { |
| 1056 | public: |
| 1057 | Shift() : shift_(LSL) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1058 | Shift(ShiftType shift) : shift_(shift) {} // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1059 | explicit Shift(uint32_t shift) : shift_(static_cast<ShiftType>(shift)) {} |
| 1060 | const Shift& GetShift() const { return *this; } |
| 1061 | ShiftType GetType() const { return shift_; } |
| 1062 | uint32_t GetValue() const { return shift_; } |
| 1063 | const char* GetName() const; |
| 1064 | bool IsLSL() const { return shift_ == LSL; } |
| 1065 | bool IsLSR() const { return shift_ == LSR; } |
| 1066 | bool IsASR() const { return shift_ == ASR; } |
| 1067 | bool IsROR() const { return shift_ == ROR; } |
| 1068 | bool IsRRX() const { return shift_ == RRX; } |
| 1069 | bool Is(Shift value) const { return shift_ == value.shift_; } |
| 1070 | bool IsNot(Shift value) const { return shift_ != value.shift_; } |
| 1071 | bool IsValidAmount(uint32_t amount) const; |
| 1072 | static const Shift NoShift; |
| 1073 | |
| 1074 | protected: |
| 1075 | void SetType(ShiftType s) { shift_ = s; } |
| 1076 | |
| 1077 | private: |
| 1078 | ShiftType shift_; |
| 1079 | }; |
| 1080 | |
| 1081 | inline std::ostream& operator<<(std::ostream& os, Shift shift) { |
| 1082 | return os << shift.GetName(); |
| 1083 | } |
| 1084 | |
| 1085 | class ImmediateShiftOperand : public Shift { |
| 1086 | public: |
| 1087 | // Constructor used for assembly. |
| 1088 | ImmediateShiftOperand(Shift shift, uint32_t amount) |
| 1089 | : Shift(shift), amount_(amount) { |
| 1090 | #ifdef VIXL_DEBUG |
| 1091 | switch (shift.GetType()) { |
| 1092 | case LSL: |
| 1093 | VIXL_ASSERT(amount <= 31); |
| 1094 | break; |
| 1095 | case ROR: |
| 1096 | VIXL_ASSERT(amount > 0); |
| 1097 | VIXL_ASSERT(amount <= 31); |
| 1098 | break; |
| 1099 | case LSR: |
| 1100 | case ASR: |
| 1101 | VIXL_ASSERT(amount > 0); |
| 1102 | VIXL_ASSERT(amount <= 32); |
| 1103 | break; |
| 1104 | case RRX: |
| 1105 | VIXL_ASSERT(amount == 0); |
| 1106 | break; |
| 1107 | default: |
| 1108 | VIXL_UNREACHABLE(); |
| 1109 | break; |
| 1110 | } |
| 1111 | #endif |
| 1112 | } |
| 1113 | // Constructor used for disassembly. |
| 1114 | ImmediateShiftOperand(int shift, int amount); |
| 1115 | uint32_t GetAmount() const { return amount_; } |
| 1116 | bool Is(const ImmediateShiftOperand& rhs) const { |
| 1117 | return amount_ == (rhs.amount_) && Shift::Is(*this); |
| 1118 | } |
| 1119 | |
| 1120 | private: |
| 1121 | uint32_t amount_; |
| 1122 | }; |
| 1123 | |
| 1124 | inline std::ostream& operator<<(std::ostream& os, |
| 1125 | ImmediateShiftOperand const& shift_operand) { |
| 1126 | if (shift_operand.IsLSL() && shift_operand.GetAmount() == 0) return os; |
| 1127 | if (shift_operand.IsRRX()) return os << ", rrx"; |
| 1128 | return os << ", " << shift_operand.GetName() << " #" |
| 1129 | << shift_operand.GetAmount(); |
| 1130 | } |
| 1131 | |
| 1132 | class RegisterShiftOperand : public Shift { |
| 1133 | public: |
| 1134 | RegisterShiftOperand(ShiftType shift, Register shift_register) |
| 1135 | : Shift(shift), shift_register_(shift_register) { |
| 1136 | VIXL_ASSERT(!IsRRX() && shift_register_.IsValid()); |
| 1137 | } |
| 1138 | const Register GetShiftRegister() const { return shift_register_; } |
| 1139 | bool Is(const RegisterShiftOperand& rhs) const { |
| 1140 | return shift_register_.Is(rhs.shift_register_) && Shift::Is(*this); |
| 1141 | } |
| 1142 | |
| 1143 | private: |
| 1144 | Register shift_register_; |
| 1145 | }; |
| 1146 | |
| 1147 | inline std::ostream& operator<<(std::ostream& s, |
| 1148 | const RegisterShiftOperand& shift_operand) { |
| 1149 | return s << shift_operand.GetName() << " " |
| 1150 | << shift_operand.GetShiftRegister(); |
| 1151 | } |
| 1152 | |
| 1153 | enum EncodingSizeType { Best, Narrow, Wide }; |
| 1154 | |
| 1155 | class EncodingSize { |
| 1156 | uint32_t size_; |
| 1157 | |
| 1158 | public: |
| 1159 | explicit EncodingSize(uint32_t size) : size_(size) {} |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1160 | EncodingSize(EncodingSizeType size) // NOLINT(runtime/explicit) |
| 1161 | : size_(size) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1162 | uint32_t GetSize() const { return size_; } |
| 1163 | const char* GetName() const; |
| 1164 | bool IsBest() const { return size_ == Best; } |
| 1165 | bool IsNarrow() const { return size_ == Narrow; } |
| 1166 | bool IsWide() const { return size_ == Wide; } |
| 1167 | }; |
| 1168 | |
| 1169 | inline std::ostream& operator<<(std::ostream& os, EncodingSize size) { |
| 1170 | return os << size.GetName(); |
| 1171 | } |
| 1172 | |
| 1173 | enum WriteBackValue { NO_WRITE_BACK, WRITE_BACK }; |
| 1174 | |
| 1175 | class WriteBack { |
| 1176 | WriteBackValue value_; |
| 1177 | |
| 1178 | public: |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1179 | WriteBack(WriteBackValue value) // NOLINT(runtime/explicit) |
| 1180 | : value_(value) {} |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1181 | explicit WriteBack(int value) |
| 1182 | : value_((value == 0) ? NO_WRITE_BACK : WRITE_BACK) {} |
| 1183 | uint32_t GetWriteBackUint32() const { return (value_ == WRITE_BACK) ? 1 : 0; } |
| 1184 | bool DoesWriteBack() const { return value_ == WRITE_BACK; } |
| 1185 | }; |
| 1186 | |
| 1187 | inline std::ostream& operator<<(std::ostream& os, WriteBack write_back) { |
| 1188 | if (write_back.DoesWriteBack()) return os << "!"; |
| 1189 | return os; |
| 1190 | } |
| 1191 | |
| 1192 | class EncodingValue { |
| 1193 | bool valid_; |
| 1194 | uint32_t encoding_value_; |
| 1195 | |
| 1196 | public: |
| 1197 | EncodingValue() { |
| 1198 | valid_ = false; |
| 1199 | encoding_value_ = 0; |
| 1200 | } |
| 1201 | bool IsValid() const { return valid_; } |
| 1202 | uint32_t GetEncodingValue() const { return encoding_value_; } |
| 1203 | void SetEncodingValue(uint32_t encoding_value) { |
| 1204 | valid_ = true; |
| 1205 | encoding_value_ = encoding_value; |
| 1206 | } |
| 1207 | }; |
| 1208 | |
| 1209 | class EncodingValueAndImmediate : public EncodingValue { |
| 1210 | uint32_t encoded_immediate_; |
| 1211 | |
| 1212 | public: |
| 1213 | EncodingValueAndImmediate() { encoded_immediate_ = 0; } |
| 1214 | uint32_t GetEncodedImmediate() const { return encoded_immediate_; } |
| 1215 | void SetEncodedImmediate(uint32_t encoded_immediate) { |
| 1216 | encoded_immediate_ = encoded_immediate; |
| 1217 | } |
| 1218 | }; |
| 1219 | |
| 1220 | class ImmediateT32 : public EncodingValue { |
| 1221 | public: |
| 1222 | explicit ImmediateT32(uint32_t imm); |
| 1223 | static bool IsImmediateT32(uint32_t imm); |
| 1224 | static uint32_t Decode(uint32_t value); |
| 1225 | }; |
| 1226 | |
| 1227 | class ImmediateA32 : public EncodingValue { |
| 1228 | public: |
| 1229 | explicit ImmediateA32(uint32_t imm); |
| 1230 | static bool IsImmediateA32(uint32_t imm); |
| 1231 | static uint32_t Decode(uint32_t value); |
| 1232 | }; |
| 1233 | |
| 1234 | // Return the encoding value of a shift type. |
| 1235 | uint32_t TypeEncodingValue(Shift shift); |
| 1236 | // Return the encoding value for a shift amount depending on the shift type. |
| 1237 | uint32_t AmountEncodingValue(Shift shift, uint32_t amount); |
| 1238 | |
| 1239 | enum MemoryBarrierType { |
| 1240 | OSHLD = 0x1, |
| 1241 | OSHST = 0x2, |
| 1242 | OSH = 0x3, |
| 1243 | NSHLD = 0x5, |
| 1244 | NSHST = 0x6, |
| 1245 | NSH = 0x7, |
| 1246 | ISHLD = 0x9, |
| 1247 | ISHST = 0xa, |
| 1248 | ISH = 0xb, |
| 1249 | LD = 0xd, |
| 1250 | ST = 0xe, |
| 1251 | SY = 0xf |
| 1252 | }; |
| 1253 | |
| 1254 | class MemoryBarrier { |
| 1255 | MemoryBarrierType type_; |
| 1256 | |
| 1257 | public: |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1258 | MemoryBarrier(MemoryBarrierType type) // NOLINT(runtime/explicit) |
| 1259 | : type_(type) {} |
| 1260 | MemoryBarrier(uint32_t type) // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1261 | : type_(static_cast<MemoryBarrierType>(type)) { |
| 1262 | VIXL_ASSERT((type & 0x3) != 0); |
| 1263 | } |
| 1264 | MemoryBarrierType GetType() const { return type_; } |
| 1265 | const char* GetName() const; |
| 1266 | }; |
| 1267 | |
| 1268 | inline std::ostream& operator<<(std::ostream& os, MemoryBarrier option) { |
| 1269 | return os << option.GetName(); |
| 1270 | } |
| 1271 | |
| 1272 | enum InterruptFlagsType { |
| 1273 | F = 0x1, |
| 1274 | I = 0x2, |
| 1275 | IF = 0x3, |
| 1276 | A = 0x4, |
| 1277 | AF = 0x5, |
| 1278 | AI = 0x6, |
| 1279 | AIF = 0x7 |
| 1280 | }; |
| 1281 | |
| 1282 | class InterruptFlags { |
| 1283 | InterruptFlagsType type_; |
| 1284 | |
| 1285 | public: |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1286 | InterruptFlags(InterruptFlagsType type) // NOLINT(runtime/explicit) |
| 1287 | : type_(type) {} |
| 1288 | InterruptFlags(uint32_t type) // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1289 | : type_(static_cast<InterruptFlagsType>(type)) { |
| 1290 | VIXL_ASSERT(type <= 7); |
| 1291 | } |
| 1292 | InterruptFlagsType GetType() const { return type_; } |
| 1293 | const char* GetName() const; |
| 1294 | }; |
| 1295 | |
| 1296 | inline std::ostream& operator<<(std::ostream& os, InterruptFlags option) { |
| 1297 | return os << option.GetName(); |
| 1298 | } |
| 1299 | |
| 1300 | enum EndiannessType { LE = 0, BE = 1 }; |
| 1301 | |
| 1302 | class Endianness { |
| 1303 | EndiannessType type_; |
| 1304 | |
| 1305 | public: |
Vincent Belliard | 60241a5 | 2016-11-10 12:41:11 -0800 | [diff] [blame] | 1306 | Endianness(EndiannessType type) : type_(type) {} // NOLINT(runtime/explicit) |
| 1307 | Endianness(uint32_t type) // NOLINT(runtime/explicit) |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1308 | : type_(static_cast<EndiannessType>(type)) { |
| 1309 | VIXL_ASSERT(type <= 1); |
| 1310 | } |
| 1311 | EndiannessType GetType() const { return type_; } |
| 1312 | const char* GetName() const; |
| 1313 | }; |
| 1314 | |
| 1315 | inline std::ostream& operator<<(std::ostream& os, Endianness endian_specifier) { |
| 1316 | return os << endian_specifier.GetName(); |
| 1317 | } |
| 1318 | |
| 1319 | enum AlignmentType { |
| 1320 | k16BitAlign = 0, |
| 1321 | k32BitAlign = 1, |
| 1322 | k64BitAlign = 2, |
| 1323 | k128BitAlign = 3, |
| 1324 | k256BitAlign = 4, |
| 1325 | kNoAlignment = 5, |
| 1326 | kBadAlignment = 6 |
| 1327 | }; |
| 1328 | |
| 1329 | class Alignment { |
| 1330 | AlignmentType align_; |
| 1331 | |
| 1332 | public: |
| 1333 | Alignment(AlignmentType align) // NOLINT(runtime/explicit) |
| 1334 | : align_(align) {} |
| 1335 | Alignment(uint32_t align) // NOLINT(runtime/explicit) |
| 1336 | : align_(static_cast<AlignmentType>(align)) { |
| 1337 | VIXL_ASSERT(align <= static_cast<uint32_t>(k256BitAlign)); |
| 1338 | } |
| 1339 | AlignmentType GetType() const { return align_; } |
| 1340 | bool Is(AlignmentType type) { return align_ == type; } |
| 1341 | }; |
| 1342 | |
| 1343 | inline std::ostream& operator<<(std::ostream& os, Alignment align) { |
| 1344 | if (align.GetType() == kBadAlignment) return os << " :??"; |
| 1345 | if (align.GetType() == kNoAlignment) return os; |
| 1346 | return os << " :" << (0x10 << static_cast<uint32_t>(align.GetType())); |
| 1347 | } |
| 1348 | |
Georgia Kouveli | 8b57c86 | 2017-03-02 15:18:58 +0000 | [diff] [blame] | 1349 | // Structure containing information on forward references. |
| 1350 | struct ReferenceInfo { |
| 1351 | int size; |
| 1352 | int min_offset; |
| 1353 | int max_offset; |
| 1354 | int alignment; // As a power of two. |
| 1355 | enum { kAlignPc, kDontAlignPc } pc_needs_aligning; |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1356 | }; |
| 1357 | |
Alexandre Rames | d383296 | 2016-07-04 15:03:43 +0100 | [diff] [blame] | 1358 | } // namespace aarch32 |
| 1359 | } // namespace vixl |
| 1360 | |
| 1361 | #endif // VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_ |