1 // Copyright 2015, VIXL authors 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 10 // notice, this list of conditions and the following disclaimer in the 11 // documentation and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may 13 // be used to endorse or promote products derived from this software 14 // without 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 18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 // POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef VIXL_AARCH32_OPERANDS_AARCH32_H_ 29 #define VIXL_AARCH32_OPERANDS_AARCH32_H_ 30 31 #include "aarch32/instructions-aarch32.h" 32 33 namespace vixl { 34 namespace aarch32 { 35 36 // Operand represents generic set of arguments to pass to an instruction. 37 // 38 // Usage: <instr> <Rd> , <Operand> 39 // 40 // where <instr> is the instruction to use (e.g., Mov(), Rsb(), etc.) 41 // <Rd> is the destination register 42 // <Operand> is the rest of the arguments to the instruction 43 // 44 // <Operand> can be one of: 45 // 46 // #<imm> - an unsigned 32-bit immediate value 47 // <Rm>, <shift> <#amount> - immediate shifted register 48 // <Rm>, <shift> <Rs> - register shifted register 49 // 50 class Operand { 51 public: 52 // { #<immediate> } 53 // where <immediate> is uint32_t. 54 // This is allowed to be an implicit constructor because Operand is 55 // a wrapper class that doesn't normally perform any type conversion. Operand(uint32_t immediate)56 Operand(uint32_t immediate) // NOLINT(runtime/explicit) 57 : imm_(immediate), 58 rm_(NoReg), 59 shift_(LSL), 60 amount_(0), 61 rs_(NoReg) {} Operand(int32_t immediate)62 Operand(int32_t immediate) // NOLINT(runtime/explicit) 63 : imm_(immediate), 64 rm_(NoReg), 65 shift_(LSL), 66 amount_(0), 67 rs_(NoReg) {} 68 69 // rm 70 // where rm is the base register 71 // This is allowed to be an implicit constructor because Operand is 72 // a wrapper class that doesn't normally perform any type conversion. Operand(Register rm)73 Operand(Register rm) // NOLINT(runtime/explicit) 74 : imm_(0), 75 rm_(rm), 76 shift_(LSL), 77 amount_(0), 78 rs_(NoReg) { 79 VIXL_ASSERT(rm_.IsValid()); 80 } 81 82 // rm, <shift> 83 // where rm is the base register, and 84 // <shift> is RRX Operand(Register rm,Shift shift)85 Operand(Register rm, Shift shift) 86 : imm_(0), rm_(rm), shift_(shift), amount_(0), rs_(NoReg) { 87 VIXL_ASSERT(rm_.IsValid()); 88 VIXL_ASSERT(shift_.IsRRX()); 89 } 90 91 // rm, <shift> #<amount> 92 // where rm is the base register, and 93 // <shift> is one of {LSL, LSR, ASR, ROR}, and 94 // <amount> is uint6_t. Operand(Register rm,Shift shift,uint32_t amount)95 Operand(Register rm, Shift shift, uint32_t amount) 96 : imm_(0), rm_(rm), shift_(shift), amount_(amount), rs_(NoReg) { 97 VIXL_ASSERT(rm_.IsValid()); 98 VIXL_ASSERT(!shift_.IsRRX()); 99 #ifdef VIXL_DEBUG 100 switch (shift_.GetType()) { 101 case LSL: 102 VIXL_ASSERT(amount_ <= 31); 103 break; 104 case ROR: 105 VIXL_ASSERT(amount_ <= 31); 106 break; 107 case LSR: 108 case ASR: 109 VIXL_ASSERT(amount_ <= 32); 110 break; 111 case RRX: 112 default: 113 VIXL_UNREACHABLE(); 114 break; 115 } 116 #endif 117 } 118 119 // rm, <shift> rs 120 // where rm is the base register, and 121 // <shift> is one of {LSL, LSR, ASR, ROR}, and 122 // rs is the shifted register Operand(Register rm,Shift shift,Register rs)123 Operand(Register rm, Shift shift, Register rs) 124 : imm_(0), rm_(rm), shift_(shift), amount_(0), rs_(rs) { 125 VIXL_ASSERT(rm_.IsValid() && rs_.IsValid()); 126 VIXL_ASSERT(!shift_.IsRRX()); 127 } 128 129 // Factory methods creating operands from any integral or pointer type. The 130 // source must fit into 32 bits. 131 template <typename T> From(T immediate)132 static Operand From(T immediate) { 133 #if __cplusplus >= 201103L 134 VIXL_STATIC_ASSERT_MESSAGE(std::is_integral<T>::value, 135 "An integral type is required to build an " 136 "immediate operand."); 137 #endif 138 // Allow both a signed or unsigned 32 bit integer to be passed, but store it 139 // as a uint32_t. The signedness information will be lost. We have to add a 140 // static_cast to make sure the compiler does not complain about implicit 64 141 // to 32 narrowing. It's perfectly acceptable for the user to pass a 64-bit 142 // value, as long as it can be encoded in 32 bits. 143 VIXL_ASSERT(IsInt32(immediate) || IsUint32(immediate)); 144 return Operand(static_cast<uint32_t>(immediate)); 145 } 146 147 template <typename T> From(T * address)148 static Operand From(T* address) { 149 uintptr_t address_as_integral = reinterpret_cast<uintptr_t>(address); 150 VIXL_ASSERT(IsUint32(address_as_integral)); 151 return Operand(static_cast<uint32_t>(address_as_integral)); 152 } 153 IsImmediate()154 bool IsImmediate() const { return !rm_.IsValid(); } 155 IsPlainRegister()156 bool IsPlainRegister() const { 157 return rm_.IsValid() && !shift_.IsRRX() && !rs_.IsValid() && (amount_ == 0); 158 } 159 IsImmediateShiftedRegister()160 bool IsImmediateShiftedRegister() const { 161 return rm_.IsValid() && !rs_.IsValid(); 162 } 163 IsRegisterShiftedRegister()164 bool IsRegisterShiftedRegister() const { 165 return rm_.IsValid() && rs_.IsValid(); 166 } 167 GetImmediate()168 uint32_t GetImmediate() const { 169 VIXL_ASSERT(IsImmediate()); 170 return imm_; 171 } 172 GetSignedImmediate()173 int32_t GetSignedImmediate() const { 174 VIXL_ASSERT(IsImmediate()); 175 int32_t result; 176 memcpy(&result, &imm_, sizeof(result)); 177 return result; 178 } 179 GetBaseRegister()180 Register GetBaseRegister() const { 181 VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister()); 182 return rm_; 183 } 184 GetShift()185 Shift GetShift() const { 186 VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister()); 187 return shift_; 188 } 189 GetShiftAmount()190 uint32_t GetShiftAmount() const { 191 VIXL_ASSERT(IsImmediateShiftedRegister()); 192 return amount_; 193 } 194 GetShiftRegister()195 Register GetShiftRegister() const { 196 VIXL_ASSERT(IsRegisterShiftedRegister()); 197 return rs_; 198 } 199 GetTypeEncodingValue()200 uint32_t GetTypeEncodingValue() const { 201 return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue(); 202 } 203 204 private: 205 // Forbid implicitely creating operands around types that cannot be encoded 206 // into a uint32_t without loss. 207 #if __cplusplus >= 201103L 208 Operand(int64_t) = delete; // NOLINT(runtime/explicit) 209 Operand(uint64_t) = delete; // NOLINT(runtime/explicit) 210 Operand(float) = delete; // NOLINT(runtime/explicit) 211 Operand(double) = delete; // NOLINT(runtime/explicit) 212 #else 213 VIXL_NO_RETURN_IN_DEBUG_MODE Operand(int64_t) { // NOLINT(runtime/explicit) 214 VIXL_UNREACHABLE(); 215 } 216 VIXL_NO_RETURN_IN_DEBUG_MODE Operand(uint64_t) { // NOLINT(runtime/explicit) 217 VIXL_UNREACHABLE(); 218 } 219 VIXL_NO_RETURN_IN_DEBUG_MODE Operand(float) { // NOLINT 220 VIXL_UNREACHABLE(); 221 } 222 VIXL_NO_RETURN_IN_DEBUG_MODE Operand(double) { // NOLINT 223 VIXL_UNREACHABLE(); 224 } 225 #endif 226 227 uint32_t imm_; 228 Register rm_; 229 Shift shift_; 230 uint32_t amount_; 231 Register rs_; 232 }; 233 234 std::ostream& operator<<(std::ostream& os, const Operand& operand); 235 236 class NeonImmediate { 237 template <typename T> 238 struct DataTypeIdentity { 239 T data_type_; 240 }; 241 242 public: 243 // { #<immediate> } 244 // where <immediate> is 32 bit number. 245 // This is allowed to be an implicit constructor because NeonImmediate is 246 // a wrapper class that doesn't normally perform any type conversion. NeonImmediate(uint32_t immediate)247 NeonImmediate(uint32_t immediate) // NOLINT(runtime/explicit) 248 : imm_(immediate), 249 immediate_type_(I32) {} NeonImmediate(int immediate)250 NeonImmediate(int immediate) // NOLINT(runtime/explicit) 251 : imm_(immediate), 252 immediate_type_(I32) {} 253 254 // { #<immediate> } 255 // where <immediate> is a 64 bit number 256 // This is allowed to be an implicit constructor because NeonImmediate is 257 // a wrapper class that doesn't normally perform any type conversion. NeonImmediate(int64_t immediate)258 NeonImmediate(int64_t immediate) // NOLINT(runtime/explicit) 259 : imm_(immediate), 260 immediate_type_(I64) {} NeonImmediate(uint64_t immediate)261 NeonImmediate(uint64_t immediate) // NOLINT(runtime/explicit) 262 : imm_(immediate), 263 immediate_type_(I64) {} 264 265 // { #<immediate> } 266 // where <immediate> is a non zero floating point number which can be encoded 267 // as an 8 bit floating point (checked by the constructor). 268 // This is allowed to be an implicit constructor because NeonImmediate is 269 // a wrapper class that doesn't normally perform any type conversion. NeonImmediate(float immediate)270 NeonImmediate(float immediate) // NOLINT(runtime/explicit) 271 : imm_(immediate), 272 immediate_type_(F32) {} NeonImmediate(double immediate)273 NeonImmediate(double immediate) // NOLINT(runtime/explicit) 274 : imm_(immediate), 275 immediate_type_(F64) {} 276 NeonImmediate(const NeonImmediate & src)277 NeonImmediate(const NeonImmediate& src) 278 : imm_(src.imm_), immediate_type_(src.immediate_type_) {} 279 280 template <typename T> GetImmediate()281 T GetImmediate() const { 282 return GetImmediate(DataTypeIdentity<T>()); 283 } 284 285 template <typename T> GetImmediate(const DataTypeIdentity<T> &)286 T GetImmediate(const DataTypeIdentity<T>&) const { 287 VIXL_ASSERT(sizeof(T) <= sizeof(uint32_t)); 288 VIXL_ASSERT(CanConvert<T>()); 289 if (immediate_type_.Is(I64)) 290 return static_cast<T>(imm_.u64_ & static_cast<T>(-1)); 291 if (immediate_type_.Is(F64) || immediate_type_.Is(F32)) return 0; 292 return static_cast<T>(imm_.u32_ & static_cast<T>(-1)); 293 } 294 GetImmediate(const DataTypeIdentity<uint64_t> &)295 uint64_t GetImmediate(const DataTypeIdentity<uint64_t>&) const { 296 VIXL_ASSERT(CanConvert<uint64_t>()); 297 if (immediate_type_.Is(I32)) return imm_.u32_; 298 if (immediate_type_.Is(F64) || immediate_type_.Is(F32)) return 0; 299 return imm_.u64_; 300 } GetImmediate(const DataTypeIdentity<float> &)301 float GetImmediate(const DataTypeIdentity<float>&) const { 302 VIXL_ASSERT(CanConvert<float>()); 303 if (immediate_type_.Is(F64)) return static_cast<float>(imm_.d_); 304 return imm_.f_; 305 } GetImmediate(const DataTypeIdentity<double> &)306 double GetImmediate(const DataTypeIdentity<double>&) const { 307 VIXL_ASSERT(CanConvert<double>()); 308 if (immediate_type_.Is(F32)) return static_cast<double>(imm_.f_); 309 return imm_.d_; 310 } 311 IsInteger32()312 bool IsInteger32() const { return immediate_type_.Is(I32); } IsInteger64()313 bool IsInteger64() const { return immediate_type_.Is(I64); } IsInteger()314 bool IsInteger() const { return IsInteger32() | IsInteger64(); } IsFloat()315 bool IsFloat() const { return immediate_type_.Is(F32); } IsDouble()316 bool IsDouble() const { return immediate_type_.Is(F64); } IsFloatZero()317 bool IsFloatZero() const { 318 if (immediate_type_.Is(F32)) return imm_.f_ == 0.0f; 319 if (immediate_type_.Is(F64)) return imm_.d_ == 0.0; 320 return false; 321 } 322 323 template <typename T> CanConvert()324 bool CanConvert() const { 325 return CanConvert(DataTypeIdentity<T>()); 326 } 327 328 template <typename T> CanConvert(const DataTypeIdentity<T> &)329 bool CanConvert(const DataTypeIdentity<T>&) const { 330 VIXL_ASSERT(sizeof(T) < sizeof(uint32_t)); 331 return (immediate_type_.Is(I32) && ((imm_.u32_ >> (8 * sizeof(T))) == 0)) || 332 (immediate_type_.Is(I64) && ((imm_.u64_ >> (8 * sizeof(T))) == 0)) || 333 (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) || 334 (immediate_type_.Is(F64) && (imm_.d_ == 0.0)); 335 } CanConvert(const DataTypeIdentity<uint32_t> &)336 bool CanConvert(const DataTypeIdentity<uint32_t>&) const { 337 return immediate_type_.Is(I32) || 338 (immediate_type_.Is(I64) && ((imm_.u64_ >> 32) == 0)) || 339 (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) || 340 (immediate_type_.Is(F64) && (imm_.d_ == 0.0)); 341 } CanConvert(const DataTypeIdentity<uint64_t> &)342 bool CanConvert(const DataTypeIdentity<uint64_t>&) const { 343 return IsInteger() || CanConvert<uint32_t>(); 344 } CanConvert(const DataTypeIdentity<float> &)345 bool CanConvert(const DataTypeIdentity<float>&) const { 346 return IsFloat() || IsDouble(); 347 } CanConvert(const DataTypeIdentity<double> &)348 bool CanConvert(const DataTypeIdentity<double>&) const { 349 return IsFloat() || IsDouble(); 350 } 351 friend std::ostream& operator<<(std::ostream& os, 352 const NeonImmediate& operand); 353 354 private: 355 union NeonImmediateType { 356 uint64_t u64_; 357 double d_; 358 uint32_t u32_; 359 float f_; NeonImmediateType(uint64_t u)360 NeonImmediateType(uint64_t u) : u64_(u) {} NeonImmediateType(int64_t u)361 NeonImmediateType(int64_t u) : u64_(u) {} NeonImmediateType(uint32_t u)362 NeonImmediateType(uint32_t u) : u32_(u) {} NeonImmediateType(int32_t u)363 NeonImmediateType(int32_t u) : u32_(u) {} NeonImmediateType(double d)364 NeonImmediateType(double d) : d_(d) {} NeonImmediateType(float f)365 NeonImmediateType(float f) : f_(f) {} NeonImmediateType(const NeonImmediateType & ref)366 NeonImmediateType(const NeonImmediateType& ref) : u64_(ref.u64_) {} 367 } imm_; 368 369 DataType immediate_type_; 370 }; 371 372 std::ostream& operator<<(std::ostream& os, const NeonImmediate& operand); 373 374 class NeonOperand { 375 public: NeonOperand(int32_t immediate)376 NeonOperand(int32_t immediate) // NOLINT(runtime/explicit) 377 : imm_(immediate), 378 rm_(NoDReg) {} NeonOperand(uint32_t immediate)379 NeonOperand(uint32_t immediate) // NOLINT(runtime/explicit) 380 : imm_(immediate), 381 rm_(NoDReg) {} NeonOperand(int64_t immediate)382 NeonOperand(int64_t immediate) // NOLINT(runtime/explicit) 383 : imm_(immediate), 384 rm_(NoDReg) {} NeonOperand(uint64_t immediate)385 NeonOperand(uint64_t immediate) // NOLINT(runtime/explicit) 386 : imm_(immediate), 387 rm_(NoDReg) {} NeonOperand(float immediate)388 NeonOperand(float immediate) // NOLINT(runtime/explicit) 389 : imm_(immediate), 390 rm_(NoDReg) {} NeonOperand(double immediate)391 NeonOperand(double immediate) // NOLINT(runtime/explicit) 392 : imm_(immediate), 393 rm_(NoDReg) {} NeonOperand(const NeonImmediate & imm)394 NeonOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 395 : imm_(imm), 396 rm_(NoDReg) {} NeonOperand(const VRegister & rm)397 NeonOperand(const VRegister& rm) // NOLINT(runtime/explicit) 398 : imm_(0), 399 rm_(rm) { 400 VIXL_ASSERT(rm_.IsValid()); 401 } 402 IsImmediate()403 bool IsImmediate() const { return !rm_.IsValid(); } IsRegister()404 bool IsRegister() const { return rm_.IsValid(); } IsFloatZero()405 bool IsFloatZero() const { 406 VIXL_ASSERT(IsImmediate()); 407 return imm_.IsFloatZero(); 408 } 409 GetNeonImmediate()410 const NeonImmediate& GetNeonImmediate() const { return imm_; } 411 GetRegister()412 VRegister GetRegister() const { 413 VIXL_ASSERT(IsRegister()); 414 return rm_; 415 } 416 417 protected: 418 NeonImmediate imm_; 419 VRegister rm_; 420 }; 421 422 std::ostream& operator<<(std::ostream& os, const NeonOperand& operand); 423 424 // SOperand represents either an immediate or a SRegister. 425 class SOperand : public NeonOperand { 426 public: 427 // #<immediate> 428 // where <immediate> is 32bit int 429 // This is allowed to be an implicit constructor because SOperand is 430 // a wrapper class that doesn't normally perform any type conversion. SOperand(int32_t immediate)431 SOperand(int32_t immediate) // NOLINT(runtime/explicit) 432 : NeonOperand(immediate) {} SOperand(uint32_t immediate)433 SOperand(uint32_t immediate) // NOLINT(runtime/explicit) 434 : NeonOperand(immediate) {} 435 // #<immediate> 436 // where <immediate> is 32bit float SOperand(float immediate)437 SOperand(float immediate) // NOLINT(runtime/explicit) 438 : NeonOperand(immediate) {} 439 // where <immediate> is 64bit float SOperand(double immediate)440 SOperand(double immediate) // NOLINT(runtime/explicit) 441 : NeonOperand(immediate) {} 442 SOperand(const NeonImmediate & imm)443 SOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 444 : NeonOperand(imm) {} 445 446 // rm 447 // This is allowed to be an implicit constructor because SOperand is 448 // a wrapper class that doesn't normally perform any type conversion. SOperand(SRegister rm)449 SOperand(SRegister rm) // NOLINT(runtime/explicit) 450 : NeonOperand(rm) {} GetRegister()451 SRegister GetRegister() const { 452 VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kSRegister)); 453 return SRegister(rm_.GetCode()); 454 } 455 }; 456 457 // DOperand represents either an immediate or a DRegister. 458 std::ostream& operator<<(std::ostream& os, const SOperand& operand); 459 460 class DOperand : public NeonOperand { 461 public: 462 // #<immediate> 463 // where <immediate> is uint32_t. 464 // This is allowed to be an implicit constructor because DOperand is 465 // a wrapper class that doesn't normally perform any type conversion. DOperand(int32_t immediate)466 DOperand(int32_t immediate) // NOLINT(runtime/explicit) 467 : NeonOperand(immediate) {} DOperand(uint32_t immediate)468 DOperand(uint32_t immediate) // NOLINT(runtime/explicit) 469 : NeonOperand(immediate) {} DOperand(int64_t immediate)470 DOperand(int64_t immediate) // NOLINT(runtime/explicit) 471 : NeonOperand(immediate) {} DOperand(uint64_t immediate)472 DOperand(uint64_t immediate) // NOLINT(runtime/explicit) 473 : NeonOperand(immediate) {} 474 475 // #<immediate> 476 // where <immediate> is a non zero floating point number which can be encoded 477 // as an 8 bit floating point (checked by the constructor). 478 // This is allowed to be an implicit constructor because DOperand is 479 // a wrapper class that doesn't normally perform any type conversion. DOperand(float immediate)480 DOperand(float immediate) // NOLINT(runtime/explicit) 481 : NeonOperand(immediate) {} DOperand(double immediate)482 DOperand(double immediate) // NOLINT(runtime/explicit) 483 : NeonOperand(immediate) {} 484 DOperand(const NeonImmediate & imm)485 DOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 486 : NeonOperand(imm) {} 487 // rm 488 // This is allowed to be an implicit constructor because DOperand is 489 // a wrapper class that doesn't normally perform any type conversion. DOperand(DRegister rm)490 DOperand(DRegister rm) // NOLINT(runtime/explicit) 491 : NeonOperand(rm) {} 492 GetRegister()493 DRegister GetRegister() const { 494 VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kDRegister)); 495 return DRegister(rm_.GetCode()); 496 } 497 }; 498 499 std::ostream& operator<<(std::ostream& os, const DOperand& operand); 500 501 // QOperand represents either an immediate or a QRegister. 502 class QOperand : public NeonOperand { 503 public: 504 // #<immediate> 505 // where <immediate> is uint32_t. 506 // This is allowed to be an implicit constructor because QOperand is 507 // a wrapper class that doesn't normally perform any type conversion. QOperand(int32_t immediate)508 QOperand(int32_t immediate) // NOLINT(runtime/explicit) 509 : NeonOperand(immediate) {} QOperand(uint32_t immediate)510 QOperand(uint32_t immediate) // NOLINT(runtime/explicit) 511 : NeonOperand(immediate) {} QOperand(int64_t immediate)512 QOperand(int64_t immediate) // NOLINT(runtime/explicit) 513 : NeonOperand(immediate) {} QOperand(uint64_t immediate)514 QOperand(uint64_t immediate) // NOLINT(runtime/explicit) 515 : NeonOperand(immediate) {} QOperand(float immediate)516 QOperand(float immediate) // NOLINT(runtime/explicit) 517 : NeonOperand(immediate) {} QOperand(double immediate)518 QOperand(double immediate) // NOLINT(runtime/explicit) 519 : NeonOperand(immediate) {} 520 QOperand(const NeonImmediate & imm)521 QOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 522 : NeonOperand(imm) {} 523 524 // rm 525 // This is allowed to be an implicit constructor because QOperand is 526 // a wrapper class that doesn't normally perform any type conversion. QOperand(QRegister rm)527 QOperand(QRegister rm) // NOLINT(runtime/explicit) 528 : NeonOperand(rm) { 529 VIXL_ASSERT(rm_.IsValid()); 530 } 531 GetRegister()532 QRegister GetRegister() const { 533 VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kQRegister)); 534 return QRegister(rm_.GetCode()); 535 } 536 }; 537 538 std::ostream& operator<<(std::ostream& os, const QOperand& operand); 539 540 class ImmediateVFP : public EncodingValue { 541 template <typename T> 542 struct FloatType { 543 typedef T base_type; 544 }; 545 546 public: ImmediateVFP(const NeonImmediate & neon_imm)547 explicit ImmediateVFP(const NeonImmediate& neon_imm) { 548 if (neon_imm.IsFloat()) { 549 const float imm = neon_imm.GetImmediate<float>(); 550 if (VFP::IsImmFP32(imm)) { 551 SetEncodingValue(VFP::FP32ToImm8(imm)); 552 } 553 } else if (neon_imm.IsDouble()) { 554 const double imm = neon_imm.GetImmediate<double>(); 555 if (VFP::IsImmFP64(imm)) { 556 SetEncodingValue(VFP::FP64ToImm8(imm)); 557 } 558 } 559 } 560 561 template <typename T> Decode(uint32_t v)562 static T Decode(uint32_t v) { 563 return Decode(v, FloatType<T>()); 564 } 565 Decode(uint32_t imm8,const FloatType<float> &)566 static float Decode(uint32_t imm8, const FloatType<float>&) { 567 return VFP::Imm8ToFP32(imm8); 568 } 569 Decode(uint32_t imm8,const FloatType<double> &)570 static double Decode(uint32_t imm8, const FloatType<double>&) { 571 return VFP::Imm8ToFP64(imm8); 572 } 573 }; 574 575 576 class ImmediateVbic : public EncodingValueAndImmediate { 577 public: 578 ImmediateVbic(DataType dt, const NeonImmediate& neon_imm); 579 static DataType DecodeDt(uint32_t cmode); 580 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 581 }; 582 583 class ImmediateVand : public ImmediateVbic { 584 public: ImmediateVand(DataType dt,const NeonImmediate neon_imm)585 ImmediateVand(DataType dt, const NeonImmediate neon_imm) 586 : ImmediateVbic(dt, neon_imm) { 587 if (IsValid()) { 588 SetEncodedImmediate(~GetEncodedImmediate() & 0xff); 589 } 590 } 591 }; 592 593 class ImmediateVmov : public EncodingValueAndImmediate { 594 public: 595 ImmediateVmov(DataType dt, const NeonImmediate& neon_imm); 596 static DataType DecodeDt(uint32_t cmode); 597 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 598 }; 599 600 class ImmediateVmvn : public EncodingValueAndImmediate { 601 public: 602 ImmediateVmvn(DataType dt, const NeonImmediate& neon_imm); 603 static DataType DecodeDt(uint32_t cmode); 604 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 605 }; 606 607 class ImmediateVorr : public EncodingValueAndImmediate { 608 public: 609 ImmediateVorr(DataType dt, const NeonImmediate& neon_imm); 610 static DataType DecodeDt(uint32_t cmode); 611 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 612 }; 613 614 class ImmediateVorn : public ImmediateVorr { 615 public: ImmediateVorn(DataType dt,const NeonImmediate & neon_imm)616 ImmediateVorn(DataType dt, const NeonImmediate& neon_imm) 617 : ImmediateVorr(dt, neon_imm) { 618 if (IsValid()) { 619 SetEncodedImmediate(~GetEncodedImmediate() & 0xff); 620 } 621 } 622 }; 623 624 // MemOperand represents the addressing mode of a load or store instruction. 625 // 626 // Usage: <instr> <Rt> , <MemOperand> 627 // 628 // where <instr> is the instruction to use (e.g., Ldr(), Str(), etc.), 629 // <Rt> is general purpose register to be transferred, 630 // <MemOperand> is the rest of the arguments to the instruction 631 // 632 // <MemOperand> can be in one of 3 addressing modes: 633 // 634 // [ <Rn>, <offset> ] == offset addressing 635 // [ <Rn>, <offset> ]! == pre-indexed addressing 636 // [ <Rn> ], <offset> == post-indexed addressing 637 // 638 // where <offset> can be one of: 639 // - an immediate constant, such as <imm8>, <imm12> 640 // - an index register <Rm> 641 // - a shifted index register <Rm>, <shift> #<amount> 642 // 643 // The index register may have an associated {+/-} sign, 644 // which if ommitted, defaults to + . 645 // 646 // We have two constructors for the offset: 647 // 648 // One with a signed value offset parameter. The value of sign_ is 649 // "sign_of(constructor's offset parameter) and the value of offset_ is 650 // "constructor's offset parameter". 651 // 652 // The other with a sign and a positive value offset parameters. The value of 653 // sign_ is "constructor's sign parameter" and the value of offset_ is 654 // "constructor's sign parameter * constructor's offset parameter". 655 // 656 // The value of offset_ reflects the effective offset. For an offset_ of 0, 657 // sign_ can be positive or negative. Otherwise, sign_ always agrees with 658 // the sign of offset_. 659 class MemOperand { 660 public: 661 // rn 662 // where rn is the general purpose base register only 663 explicit MemOperand(Register rn, AddrMode addrmode = Offset) rn_(rn)664 : rn_(rn), 665 offset_(0), 666 sign_(plus), 667 rm_(NoReg), 668 shift_(LSL), 669 shift_amount_(0), 670 addrmode_(addrmode | kMemOperandRegisterOnly) { 671 VIXL_ASSERT(rn_.IsValid()); 672 } 673 674 // rn, #<imm> 675 // where rn is the general purpose base register, 676 // <imm> is a 32-bit offset to add to rn 677 // 678 // Note: if rn is PC, then this form is equivalent to a "label" 679 // Note: the second constructor allow minus zero (-0). 680 MemOperand(Register rn, int32_t offset, AddrMode addrmode = Offset) rn_(rn)681 : rn_(rn), 682 offset_(offset), 683 sign_((offset < 0) ? minus : plus), 684 rm_(NoReg), 685 shift_(LSL), 686 shift_amount_(0), 687 addrmode_(addrmode) { 688 VIXL_ASSERT(rn_.IsValid()); 689 } 690 MemOperand(Register rn, Sign sign, int32_t offset, AddrMode addrmode = Offset) rn_(rn)691 : rn_(rn), 692 offset_(sign.IsPlus() ? offset : -offset), 693 sign_(sign), 694 rm_(NoReg), 695 shift_(LSL), 696 shift_amount_(0), 697 addrmode_(addrmode) { 698 VIXL_ASSERT(rn_.IsValid()); 699 // With this constructor, the sign must only be specified by "sign". 700 VIXL_ASSERT(offset >= 0); 701 } 702 703 // rn, {+/-}rm 704 // where rn is the general purpose base register, 705 // {+/-} is the sign of the index register, 706 // rm is the general purpose index register, 707 MemOperand(Register rn, Sign sign, Register rm, AddrMode addrmode = Offset) rn_(rn)708 : rn_(rn), 709 offset_(0), 710 sign_(sign), 711 rm_(rm), 712 shift_(LSL), 713 shift_amount_(0), 714 addrmode_(addrmode) { 715 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 716 } 717 718 // rn, rm 719 // where rn is the general purpose base register, 720 // rm is the general purpose index register, 721 MemOperand(Register rn, Register rm, AddrMode addrmode = Offset) rn_(rn)722 : rn_(rn), 723 offset_(0), 724 sign_(plus), 725 rm_(rm), 726 shift_(LSL), 727 shift_amount_(0), 728 addrmode_(addrmode) { 729 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 730 } 731 732 // rn, {+/-}rm, <shift> 733 // where rn is the general purpose base register, 734 // {+/-} is the sign of the index register, 735 // rm is the general purpose index register, 736 // <shift> is RRX, applied to value from rm 737 MemOperand(Register rn, 738 Sign sign, 739 Register rm, 740 Shift shift, 741 AddrMode addrmode = Offset) rn_(rn)742 : rn_(rn), 743 offset_(0), 744 sign_(sign), 745 rm_(rm), 746 shift_(shift), 747 shift_amount_(0), 748 addrmode_(addrmode) { 749 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 750 VIXL_ASSERT(shift_.IsRRX()); 751 } 752 753 // rn, rm, <shift> 754 // where rn is the general purpose base register, 755 // rm is the general purpose index register, 756 // <shift> is RRX, applied to value from rm 757 MemOperand(Register rn, Register rm, Shift shift, AddrMode addrmode = Offset) rn_(rn)758 : rn_(rn), 759 offset_(0), 760 sign_(plus), 761 rm_(rm), 762 shift_(shift), 763 shift_amount_(0), 764 addrmode_(addrmode) { 765 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 766 VIXL_ASSERT(shift_.IsRRX()); 767 } 768 769 // rn, {+/-}rm, <shift> #<amount> 770 // where rn is the general purpose base register, 771 // {+/-} is the sign of the index register, 772 // rm is the general purpose index register, 773 // <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm 774 // <shift_amount> is optional size to apply to value from rm 775 MemOperand(Register rn, 776 Sign sign, 777 Register rm, 778 Shift shift, 779 uint32_t shift_amount, 780 AddrMode addrmode = Offset) rn_(rn)781 : rn_(rn), 782 offset_(0), 783 sign_(sign), 784 rm_(rm), 785 shift_(shift), 786 shift_amount_(shift_amount), 787 addrmode_(addrmode) { 788 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 789 CheckShift(); 790 } 791 792 // rn, rm, <shift> #<amount> 793 // where rn is the general purpose base register, 794 // rm is the general purpose index register, 795 // <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm 796 // <shift_amount> is optional size to apply to value from rm 797 MemOperand(Register rn, 798 Register rm, 799 Shift shift, 800 uint32_t shift_amount, 801 AddrMode addrmode = Offset) rn_(rn)802 : rn_(rn), 803 offset_(0), 804 sign_(plus), 805 rm_(rm), 806 shift_(shift), 807 shift_amount_(shift_amount), 808 addrmode_(addrmode) { 809 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 810 CheckShift(); 811 } 812 GetBaseRegister()813 Register GetBaseRegister() const { return rn_; } GetOffsetImmediate()814 int32_t GetOffsetImmediate() const { return offset_; } 815 bool IsOffsetImmediateWithinRange(int min, 816 int max, 817 int multiple_of = 1) const { 818 return (offset_ >= min) && (offset_ <= max) && 819 ((offset_ % multiple_of) == 0); 820 } GetSign()821 Sign GetSign() const { return sign_; } GetOffsetRegister()822 Register GetOffsetRegister() const { return rm_; } GetShift()823 Shift GetShift() const { return shift_; } GetShiftAmount()824 unsigned GetShiftAmount() const { return shift_amount_; } GetAddrMode()825 AddrMode GetAddrMode() const { 826 return static_cast<AddrMode>(addrmode_ & kMemOperandAddrModeMask); 827 } IsRegisterOnly()828 bool IsRegisterOnly() const { 829 return (addrmode_ & kMemOperandRegisterOnly) != 0; 830 } 831 IsImmediate()832 bool IsImmediate() const { return !rm_.IsValid(); } IsImmediateZero()833 bool IsImmediateZero() const { return !rm_.IsValid() && (offset_ == 0); } IsPlainRegister()834 bool IsPlainRegister() const { 835 return rm_.IsValid() && shift_.IsLSL() && (shift_amount_ == 0); 836 } IsShiftedRegister()837 bool IsShiftedRegister() const { return rm_.IsValid(); } IsImmediateOffset()838 bool IsImmediateOffset() const { 839 return (GetAddrMode() == Offset) && !rm_.IsValid(); 840 } IsImmediateZeroOffset()841 bool IsImmediateZeroOffset() const { 842 return (GetAddrMode() == Offset) && !rm_.IsValid() && (offset_ == 0); 843 } IsRegisterOffset()844 bool IsRegisterOffset() const { 845 return (GetAddrMode() == Offset) && rm_.IsValid() && shift_.IsLSL() && 846 (shift_amount_ == 0); 847 } IsShiftedRegisterOffset()848 bool IsShiftedRegisterOffset() const { 849 return (GetAddrMode() == Offset) && rm_.IsValid(); 850 } GetTypeEncodingValue()851 uint32_t GetTypeEncodingValue() const { 852 return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue(); 853 } IsOffset()854 bool IsOffset() const { return GetAddrMode() == Offset; } IsPreIndex()855 bool IsPreIndex() const { return GetAddrMode() == PreIndex; } IsPostIndex()856 bool IsPostIndex() const { return GetAddrMode() == PostIndex; } IsShiftValid()857 bool IsShiftValid() const { return shift_.IsValidAmount(shift_amount_); } 858 859 private: 860 static const int kMemOperandRegisterOnly = 0x1000; 861 static const int kMemOperandAddrModeMask = 0xfff; CheckShift()862 void CheckShift() { 863 #ifdef VIXL_DEBUG 864 // Disallow any zero shift other than RRX #0 and LSL #0 . 865 if ((shift_amount_ == 0) && shift_.IsRRX()) return; 866 if ((shift_amount_ == 0) && !shift_.IsLSL()) { 867 VIXL_ABORT_WITH_MSG( 868 "A shift by 0 is only accepted in " 869 "the case of lsl and will be treated as " 870 "no shift.\n"); 871 } 872 switch (shift_.GetType()) { 873 case LSL: 874 VIXL_ASSERT(shift_amount_ <= 31); 875 break; 876 case ROR: 877 VIXL_ASSERT(shift_amount_ <= 31); 878 break; 879 case LSR: 880 case ASR: 881 VIXL_ASSERT(shift_amount_ <= 32); 882 break; 883 case RRX: 884 default: 885 VIXL_UNREACHABLE(); 886 break; 887 } 888 #endif 889 } 890 Register rn_; 891 int32_t offset_; 892 Sign sign_; 893 Register rm_; 894 Shift shift_; 895 uint32_t shift_amount_; 896 uint32_t addrmode_; 897 }; 898 899 std::ostream& operator<<(std::ostream& os, const MemOperand& operand); 900 901 class AlignedMemOperand : public MemOperand { 902 public: 903 AlignedMemOperand(Register rn, Alignment align, AddrMode addrmode = Offset) MemOperand(rn,addrmode)904 : MemOperand(rn, addrmode), align_(align) { 905 VIXL_ASSERT(addrmode != PreIndex); 906 } 907 AlignedMemOperand(Register rn,Alignment align,Register rm,AddrMode addrmode)908 AlignedMemOperand(Register rn, 909 Alignment align, 910 Register rm, 911 AddrMode addrmode) 912 : MemOperand(rn, rm, addrmode), align_(align) { 913 VIXL_ASSERT(addrmode != PreIndex); 914 } 915 GetAlignment()916 Alignment GetAlignment() const { return align_; } 917 918 private: 919 Alignment align_; 920 }; 921 922 std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand); 923 924 } // namespace aarch32 925 } // namespace vixl 926 927 #endif // VIXL_AARCH32_OPERANDS_AARCH32_H_ 928