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