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. 56 Operand(uint32_t immediate) // NOLINT(runtime/explicit) 57 : imm_(immediate), 58 rm_(NoReg), 59 shift_(LSL), 60 amount_(0), 61 rs_(NoReg) {} 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. 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 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. 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 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> 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> 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 154 bool IsImmediate() const { return !rm_.IsValid(); } 155 156 bool IsPlainRegister() const { 157 return rm_.IsValid() && !shift_.IsRRX() && !rs_.IsValid() && (amount_ == 0); 158 } 159 160 bool IsImmediateShiftedRegister() const { 161 return rm_.IsValid() && !rs_.IsValid(); 162 } 163 164 bool IsRegisterShiftedRegister() const { 165 return rm_.IsValid() && rs_.IsValid(); 166 } 167 168 uint32_t GetImmediate() const { 169 VIXL_ASSERT(IsImmediate()); 170 return imm_; 171 } 172 173 int32_t GetSignedImmediate() const { 174 VIXL_ASSERT(IsImmediate()); 175 int32_t result; 176 memcpy(&result, &imm_, sizeof(result)); 177 return result; 178 } 179 180 Register GetBaseRegister() const { 181 VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister()); 182 return rm_; 183 } 184 185 Shift GetShift() const { 186 VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister()); 187 return shift_; 188 } 189 190 uint32_t GetShiftAmount() const { 191 VIXL_ASSERT(IsImmediateShiftedRegister()); 192 return amount_; 193 } 194 195 Register GetShiftRegister() const { 196 VIXL_ASSERT(IsRegisterShiftedRegister()); 197 return rs_; 198 } 199 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. 247 NeonImmediate(uint32_t immediate) // NOLINT(runtime/explicit) 248 : imm_(immediate), 249 immediate_type_(I32) {} 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. 258 NeonImmediate(int64_t immediate) // NOLINT(runtime/explicit) 259 : imm_(immediate), 260 immediate_type_(I64) {} 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. 270 NeonImmediate(float immediate) // NOLINT(runtime/explicit) 271 : imm_(immediate), 272 immediate_type_(F32) {} 273 NeonImmediate(double immediate) // NOLINT(runtime/explicit) 274 : imm_(immediate), 275 immediate_type_(F64) {} 276 277 NeonImmediate(const NeonImmediate& src) 278 : imm_(src.imm_), immediate_type_(src.immediate_type_) {} 279 280 template <typename T> 281 T GetImmediate() const { 282 return GetImmediate(DataTypeIdentity<T>()); 283 } 284 285 template <typename 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 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 } 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 } 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 312 bool IsInteger32() const { return immediate_type_.Is(I32); } 313 bool IsInteger64() const { return immediate_type_.Is(I64); } 314 bool IsInteger() const { return IsInteger32() | IsInteger64(); } 315 bool IsFloat() const { return immediate_type_.Is(F32); } 316 bool IsDouble() const { return immediate_type_.Is(F64); } 317 318 template <typename T> 319 bool CanConvert() const { 320 return CanConvert(DataTypeIdentity<T>()); 321 } 322 323 template <typename T> 324 bool CanConvert(const DataTypeIdentity<T>&) const { 325 VIXL_ASSERT(sizeof(T) < sizeof(uint32_t)); 326 return (immediate_type_.Is(I32) && ((imm_.u32_ >> (8 * sizeof(T))) == 0)) || 327 (immediate_type_.Is(I64) && ((imm_.u64_ >> (8 * sizeof(T))) == 0)) || 328 (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) || 329 (immediate_type_.Is(F64) && (imm_.d_ == 0.0)); 330 } 331 bool CanConvert(const DataTypeIdentity<uint32_t>&) const { 332 return immediate_type_.Is(I32) || 333 (immediate_type_.Is(I64) && ((imm_.u64_ >> 32) == 0)) || 334 (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) || 335 (immediate_type_.Is(F64) && (imm_.d_ == 0.0)); 336 } 337 bool CanConvert(const DataTypeIdentity<uint64_t>&) const { 338 return IsInteger() || CanConvert<uint32_t>(); 339 } 340 bool CanConvert(const DataTypeIdentity<float>&) const { 341 return IsFloat() || IsDouble(); 342 } 343 bool CanConvert(const DataTypeIdentity<double>&) const { 344 return IsFloat() || IsDouble(); 345 } 346 friend std::ostream& operator<<(std::ostream& os, 347 const NeonImmediate& operand); 348 349 private: 350 union NeonImmediateType { 351 uint64_t u64_; 352 double d_; 353 uint32_t u32_; 354 float f_; 355 NeonImmediateType(uint64_t u) : u64_(u) {} 356 NeonImmediateType(int64_t u) : u64_(u) {} 357 NeonImmediateType(uint32_t u) : u32_(u) {} 358 NeonImmediateType(int32_t u) : u32_(u) {} 359 NeonImmediateType(double d) : d_(d) {} 360 NeonImmediateType(float f) : f_(f) {} 361 NeonImmediateType(const NeonImmediateType& ref) : u64_(ref.u64_) {} 362 } imm_; 363 364 DataType immediate_type_; 365 }; 366 367 std::ostream& operator<<(std::ostream& os, const NeonImmediate& operand); 368 369 class NeonOperand { 370 public: 371 NeonOperand(int32_t immediate) // NOLINT(runtime/explicit) 372 : imm_(immediate), 373 rm_(NoDReg) {} 374 NeonOperand(uint32_t immediate) // NOLINT(runtime/explicit) 375 : imm_(immediate), 376 rm_(NoDReg) {} 377 NeonOperand(int64_t immediate) // NOLINT(runtime/explicit) 378 : imm_(immediate), 379 rm_(NoDReg) {} 380 NeonOperand(uint64_t immediate) // NOLINT(runtime/explicit) 381 : imm_(immediate), 382 rm_(NoDReg) {} 383 NeonOperand(float immediate) // NOLINT(runtime/explicit) 384 : imm_(immediate), 385 rm_(NoDReg) {} 386 NeonOperand(double immediate) // NOLINT(runtime/explicit) 387 : imm_(immediate), 388 rm_(NoDReg) {} 389 NeonOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 390 : imm_(imm), 391 rm_(NoDReg) {} 392 NeonOperand(const VRegister& rm) // NOLINT(runtime/explicit) 393 : imm_(0), 394 rm_(rm) { 395 VIXL_ASSERT(rm_.IsValid()); 396 } 397 398 bool IsImmediate() const { return !rm_.IsValid(); } 399 bool IsRegister() const { return rm_.IsValid(); } 400 401 const NeonImmediate& GetNeonImmediate() const { return imm_; } 402 403 VRegister GetRegister() const { 404 VIXL_ASSERT(IsRegister()); 405 return rm_; 406 } 407 408 protected: 409 NeonImmediate imm_; 410 VRegister rm_; 411 }; 412 413 std::ostream& operator<<(std::ostream& os, const NeonOperand& operand); 414 415 // SOperand represents either an immediate or a SRegister. 416 class SOperand : public NeonOperand { 417 public: 418 // #<immediate> 419 // where <immediate> is 32bit int 420 // This is allowed to be an implicit constructor because SOperand is 421 // a wrapper class that doesn't normally perform any type conversion. 422 SOperand(int32_t immediate) // NOLINT(runtime/explicit) 423 : NeonOperand(immediate) {} 424 SOperand(uint32_t immediate) // NOLINT(runtime/explicit) 425 : NeonOperand(immediate) {} 426 // #<immediate> 427 // where <immediate> is 32bit float 428 SOperand(float immediate) // NOLINT(runtime/explicit) 429 : NeonOperand(immediate) {} 430 431 SOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 432 : NeonOperand(imm) {} 433 434 // rm 435 // This is allowed to be an implicit constructor because SOperand is 436 // a wrapper class that doesn't normally perform any type conversion. 437 SOperand(SRegister rm) // NOLINT(runtime/explicit) 438 : NeonOperand(rm) {} 439 SRegister GetRegister() const { 440 VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kSRegister)); 441 return SRegister(rm_.GetCode()); 442 } 443 }; 444 445 // DOperand represents either an immediate or a DRegister. 446 std::ostream& operator<<(std::ostream& os, const SOperand& operand); 447 448 class DOperand : public NeonOperand { 449 public: 450 // #<immediate> 451 // where <immediate> is uint32_t. 452 // This is allowed to be an implicit constructor because DOperand is 453 // a wrapper class that doesn't normally perform any type conversion. 454 DOperand(int32_t immediate) // NOLINT(runtime/explicit) 455 : NeonOperand(immediate) {} 456 DOperand(uint32_t immediate) // NOLINT(runtime/explicit) 457 : NeonOperand(immediate) {} 458 DOperand(int64_t immediate) // NOLINT(runtime/explicit) 459 : NeonOperand(immediate) {} 460 DOperand(uint64_t immediate) // NOLINT(runtime/explicit) 461 : NeonOperand(immediate) {} 462 463 // #<immediate> 464 // where <immediate> is a non zero floating point number which can be encoded 465 // as an 8 bit floating point (checked by the constructor). 466 // This is allowed to be an implicit constructor because DOperand is 467 // a wrapper class that doesn't normally perform any type conversion. 468 DOperand(float immediate) // NOLINT(runtime/explicit) 469 : NeonOperand(immediate) {} 470 DOperand(double immediate) // NOLINT(runtime/explicit) 471 : NeonOperand(immediate) {} 472 473 DOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 474 : NeonOperand(imm) {} 475 // rm 476 // This is allowed to be an implicit constructor because DOperand is 477 // a wrapper class that doesn't normally perform any type conversion. 478 DOperand(DRegister rm) // NOLINT(runtime/explicit) 479 : NeonOperand(rm) {} 480 481 DRegister GetRegister() const { 482 VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kDRegister)); 483 return DRegister(rm_.GetCode()); 484 } 485 }; 486 487 std::ostream& operator<<(std::ostream& os, const DOperand& operand); 488 489 // QOperand represents either an immediate or a QRegister. 490 class QOperand : public NeonOperand { 491 public: 492 // #<immediate> 493 // where <immediate> is uint32_t. 494 // This is allowed to be an implicit constructor because QOperand is 495 // a wrapper class that doesn't normally perform any type conversion. 496 QOperand(int32_t immediate) // NOLINT(runtime/explicit) 497 : NeonOperand(immediate) {} 498 QOperand(uint32_t immediate) // NOLINT(runtime/explicit) 499 : NeonOperand(immediate) {} 500 QOperand(int64_t immediate) // NOLINT(runtime/explicit) 501 : NeonOperand(immediate) {} 502 QOperand(uint64_t immediate) // NOLINT(runtime/explicit) 503 : NeonOperand(immediate) {} 504 QOperand(float immediate) // NOLINT(runtime/explicit) 505 : NeonOperand(immediate) {} 506 QOperand(double immediate) // NOLINT(runtime/explicit) 507 : NeonOperand(immediate) {} 508 509 QOperand(const NeonImmediate& imm) // NOLINT(runtime/explicit) 510 : NeonOperand(imm) {} 511 512 // rm 513 // This is allowed to be an implicit constructor because QOperand is 514 // a wrapper class that doesn't normally perform any type conversion. 515 QOperand(QRegister rm) // NOLINT(runtime/explicit) 516 : NeonOperand(rm) { 517 VIXL_ASSERT(rm_.IsValid()); 518 } 519 520 QRegister GetRegister() const { 521 VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kQRegister)); 522 return QRegister(rm_.GetCode()); 523 } 524 }; 525 526 std::ostream& operator<<(std::ostream& os, const QOperand& operand); 527 528 class ImmediateVFP : public EncodingValue { 529 template <typename T> 530 struct FloatType { 531 typedef T base_type; 532 }; 533 534 public: 535 explicit ImmediateVFP(const NeonImmediate& neon_imm) { 536 if (neon_imm.IsFloat()) { 537 const float imm = neon_imm.GetImmediate<float>(); 538 if (VFP::IsImmFP32(imm)) { 539 SetEncodingValue(VFP::FP32ToImm8(imm)); 540 } 541 } else if (neon_imm.IsDouble()) { 542 const double imm = neon_imm.GetImmediate<double>(); 543 if (VFP::IsImmFP64(imm)) { 544 SetEncodingValue(VFP::FP32ToImm8(imm)); 545 } 546 } 547 } 548 549 template <typename T> 550 static T Decode(uint32_t v) { 551 return Decode(v, FloatType<T>()); 552 } 553 554 static float Decode(uint32_t imm8, const FloatType<float>&) { 555 return VFP::Imm8ToFP32(imm8); 556 } 557 558 static double Decode(uint32_t imm8, const FloatType<double>&) { 559 return VFP::Imm8ToFP64(imm8); 560 } 561 }; 562 563 564 class ImmediateVbic : public EncodingValueAndImmediate { 565 public: 566 ImmediateVbic(DataType dt, const NeonImmediate& neon_imm); 567 static DataType DecodeDt(uint32_t cmode); 568 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 569 }; 570 571 class ImmediateVand : public ImmediateVbic { 572 public: 573 ImmediateVand(DataType dt, const NeonImmediate neon_imm) 574 : ImmediateVbic(dt, neon_imm) { 575 if (IsValid()) { 576 SetEncodedImmediate(~GetEncodedImmediate() & 0xff); 577 } 578 } 579 }; 580 581 class ImmediateVmov : public EncodingValueAndImmediate { 582 public: 583 ImmediateVmov(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 ImmediateVmvn : public EncodingValueAndImmediate { 589 public: 590 ImmediateVmvn(DataType dt, const NeonImmediate& neon_imm); 591 static DataType DecodeDt(uint32_t cmode); 592 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 593 }; 594 595 class ImmediateVorr : public EncodingValueAndImmediate { 596 public: 597 ImmediateVorr(DataType dt, const NeonImmediate& neon_imm); 598 static DataType DecodeDt(uint32_t cmode); 599 static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate); 600 }; 601 602 class ImmediateVorn : public ImmediateVorr { 603 public: 604 ImmediateVorn(DataType dt, const NeonImmediate& neon_imm) 605 : ImmediateVorr(dt, neon_imm) { 606 if (IsValid()) { 607 SetEncodedImmediate(~GetEncodedImmediate() & 0xff); 608 } 609 } 610 }; 611 612 // MemOperand represents the addressing mode of a load or store instruction. 613 // 614 // Usage: <instr> <Rt> , <MemOperand> 615 // 616 // where <instr> is the instruction to use (e.g., Ldr(), Str(), etc.), 617 // <Rt> is general purpose register to be transferred, 618 // <MemOperand> is the rest of the arguments to the instruction 619 // 620 // <MemOperand> can be in one of 3 addressing modes: 621 // 622 // [ <Rn>, <offset> ] == offset addressing 623 // [ <Rn>, <offset> ]! == pre-indexed addressing 624 // [ <Rn> ], <offset> == post-indexed addressing 625 // 626 // where <offset> can be one of: 627 // - an immediate constant, such as <imm8>, <imm12> 628 // - an index register <Rm> 629 // - a shifted index register <Rm>, <shift> #<amount> 630 // 631 // The index register may have an associated {+/-} sign, 632 // which if ommitted, defaults to + . 633 // 634 // We have two constructors for the offset: 635 // 636 // One with a signed value offset parameter. The value of sign_ is 637 // "sign_of(constructor's offset parameter) and the value of offset_ is 638 // "constructor's offset parameter". 639 // 640 // The other with a sign and a positive value offset parameters. The value of 641 // sign_ is "constructor's sign parameter" and the value of offset_ is 642 // "constructor's sign parameter * constructor's offset parameter". 643 // 644 // The value of offset_ reflects the effective offset. For an offset_ of 0, 645 // sign_ can be positive or negative. Otherwise, sign_ always agrees with 646 // the sign of offset_. 647 class MemOperand { 648 public: 649 // rn 650 // where rn is the general purpose base register only 651 explicit MemOperand(Register rn, AddrMode addrmode = Offset) 652 : rn_(rn), 653 offset_(0), 654 sign_(plus), 655 rm_(NoReg), 656 shift_(LSL), 657 shift_amount_(0), 658 addrmode_(addrmode | kMemOperandRegisterOnly) { 659 VIXL_ASSERT(rn_.IsValid()); 660 } 661 662 // rn, #<imm> 663 // where rn is the general purpose base register, 664 // <imm> is a 32-bit offset to add to rn 665 // 666 // Note: if rn is PC, then this form is equivalent to a "label" 667 // Note: the second constructor allow minus zero (-0). 668 MemOperand(Register rn, int32_t offset, AddrMode addrmode = Offset) 669 : rn_(rn), 670 offset_(offset), 671 sign_((offset < 0) ? minus : plus), 672 rm_(NoReg), 673 shift_(LSL), 674 shift_amount_(0), 675 addrmode_(addrmode) { 676 VIXL_ASSERT(rn_.IsValid()); 677 } 678 MemOperand(Register rn, Sign sign, int32_t offset, AddrMode addrmode = Offset) 679 : rn_(rn), 680 offset_(sign.IsPlus() ? offset : -offset), 681 sign_(sign), 682 rm_(NoReg), 683 shift_(LSL), 684 shift_amount_(0), 685 addrmode_(addrmode) { 686 VIXL_ASSERT(rn_.IsValid()); 687 // With this constructor, the sign must only be specified by "sign". 688 VIXL_ASSERT(offset >= 0); 689 } 690 691 // rn, {+/-}rm 692 // where rn is the general purpose base register, 693 // {+/-} is the sign of the index register, 694 // rm is the general purpose index register, 695 MemOperand(Register rn, Sign sign, Register rm, AddrMode addrmode = Offset) 696 : rn_(rn), 697 offset_(0), 698 sign_(sign), 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 707 // where rn is the general purpose base register, 708 // rm is the general purpose index register, 709 MemOperand(Register rn, Register rm, AddrMode addrmode = Offset) 710 : rn_(rn), 711 offset_(0), 712 sign_(plus), 713 rm_(rm), 714 shift_(LSL), 715 shift_amount_(0), 716 addrmode_(addrmode) { 717 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 718 } 719 720 // rn, {+/-}rm, <shift> 721 // where rn is the general purpose base register, 722 // {+/-} is the sign of the index register, 723 // rm is the general purpose index register, 724 // <shift> is RRX, applied to value from rm 725 MemOperand(Register rn, 726 Sign sign, 727 Register rm, 728 Shift shift, 729 AddrMode addrmode = Offset) 730 : rn_(rn), 731 offset_(0), 732 sign_(sign), 733 rm_(rm), 734 shift_(shift), 735 shift_amount_(0), 736 addrmode_(addrmode) { 737 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 738 VIXL_ASSERT(shift_.IsRRX()); 739 } 740 741 // rn, rm, <shift> 742 // where rn is the general purpose base register, 743 // rm is the general purpose index register, 744 // <shift> is RRX, applied to value from rm 745 MemOperand(Register rn, Register rm, Shift shift, AddrMode addrmode = Offset) 746 : rn_(rn), 747 offset_(0), 748 sign_(plus), 749 rm_(rm), 750 shift_(shift), 751 shift_amount_(0), 752 addrmode_(addrmode) { 753 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 754 VIXL_ASSERT(shift_.IsRRX()); 755 } 756 757 // rn, {+/-}rm, <shift> #<amount> 758 // where rn is the general purpose base register, 759 // {+/-} is the sign of the index register, 760 // rm is the general purpose index register, 761 // <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm 762 // <shift_amount> is optional size to apply to value from rm 763 MemOperand(Register rn, 764 Sign sign, 765 Register rm, 766 Shift shift, 767 uint32_t shift_amount, 768 AddrMode addrmode = Offset) 769 : rn_(rn), 770 offset_(0), 771 sign_(sign), 772 rm_(rm), 773 shift_(shift), 774 shift_amount_(shift_amount), 775 addrmode_(addrmode) { 776 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 777 CheckShift(); 778 } 779 780 // rn, rm, <shift> #<amount> 781 // where rn is the general purpose base register, 782 // rm is the general purpose index register, 783 // <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm 784 // <shift_amount> is optional size to apply to value from rm 785 MemOperand(Register rn, 786 Register rm, 787 Shift shift, 788 uint32_t shift_amount, 789 AddrMode addrmode = Offset) 790 : rn_(rn), 791 offset_(0), 792 sign_(plus), 793 rm_(rm), 794 shift_(shift), 795 shift_amount_(shift_amount), 796 addrmode_(addrmode) { 797 VIXL_ASSERT(rn_.IsValid() && rm_.IsValid()); 798 CheckShift(); 799 } 800 801 Register GetBaseRegister() const { return rn_; } 802 int32_t GetOffsetImmediate() const { return offset_; } 803 bool IsOffsetImmediateWithinRange(int min, 804 int max, 805 int multiple_of = 1) const { 806 return (offset_ >= min) && (offset_ <= max) && 807 ((offset_ % multiple_of) == 0); 808 } 809 Sign GetSign() const { return sign_; } 810 Register GetOffsetRegister() const { return rm_; } 811 Shift GetShift() const { return shift_; } 812 unsigned GetShiftAmount() const { return shift_amount_; } 813 AddrMode GetAddrMode() const { 814 return static_cast<AddrMode>(addrmode_ & kMemOperandAddrModeMask); 815 } 816 bool IsRegisterOnly() const { 817 return (addrmode_ & kMemOperandRegisterOnly) != 0; 818 } 819 820 bool IsImmediate() const { return !rm_.IsValid(); } 821 bool IsImmediateZero() const { return !rm_.IsValid() && (offset_ == 0); } 822 bool IsPlainRegister() const { 823 return rm_.IsValid() && shift_.IsLSL() && (shift_amount_ == 0); 824 } 825 bool IsShiftedRegister() const { return rm_.IsValid(); } 826 bool IsImmediateOffset() const { 827 return (GetAddrMode() == Offset) && !rm_.IsValid(); 828 } 829 bool IsImmediateZeroOffset() const { 830 return (GetAddrMode() == Offset) && !rm_.IsValid() && (offset_ == 0); 831 } 832 bool IsRegisterOffset() const { 833 return (GetAddrMode() == Offset) && rm_.IsValid() && shift_.IsLSL() && 834 (shift_amount_ == 0); 835 } 836 bool IsShiftedRegisterOffset() const { 837 return (GetAddrMode() == Offset) && rm_.IsValid(); 838 } 839 uint32_t GetTypeEncodingValue() const { 840 return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue(); 841 } 842 bool IsOffset() const { return GetAddrMode() == Offset; } 843 bool IsPreIndex() const { return GetAddrMode() == PreIndex; } 844 bool IsPostIndex() const { return GetAddrMode() == PostIndex; } 845 bool IsShiftValid() const { return shift_.IsValidAmount(shift_amount_); } 846 847 private: 848 static const int kMemOperandRegisterOnly = 0x1000; 849 static const int kMemOperandAddrModeMask = 0xfff; 850 void CheckShift() { 851 #ifdef VIXL_DEBUG 852 // Disallow any zero shift other than RRX #0 and LSL #0 . 853 if ((shift_amount_ == 0) && shift_.IsRRX()) return; 854 if ((shift_amount_ == 0) && !shift_.IsLSL()) { 855 VIXL_ABORT_WITH_MSG( 856 "A shift by 0 is only accepted in " 857 "the case of lsl and will be treated as " 858 "no shift.\n"); 859 } 860 switch (shift_.GetType()) { 861 case LSL: 862 VIXL_ASSERT(shift_amount_ <= 31); 863 break; 864 case ROR: 865 VIXL_ASSERT(shift_amount_ <= 31); 866 break; 867 case LSR: 868 case ASR: 869 VIXL_ASSERT(shift_amount_ <= 32); 870 break; 871 case RRX: 872 default: 873 VIXL_UNREACHABLE(); 874 break; 875 } 876 #endif 877 } 878 Register rn_; 879 int32_t offset_; 880 Sign sign_; 881 Register rm_; 882 Shift shift_; 883 uint32_t shift_amount_; 884 uint32_t addrmode_; 885 }; 886 887 std::ostream& operator<<(std::ostream& os, const MemOperand& operand); 888 889 class AlignedMemOperand : public MemOperand { 890 public: 891 AlignedMemOperand(Register rn, Alignment align, AddrMode addrmode = Offset) 892 : MemOperand(rn, addrmode), align_(align) { 893 VIXL_ASSERT(addrmode != PreIndex); 894 } 895 896 AlignedMemOperand(Register rn, 897 Alignment align, 898 Register rm, 899 AddrMode addrmode) 900 : MemOperand(rn, rm, addrmode), align_(align) { 901 VIXL_ASSERT(addrmode != PreIndex); 902 } 903 904 Alignment GetAlignment() const { return align_; } 905 906 private: 907 Alignment align_; 908 }; 909 910 std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand); 911 912 } // namespace aarch32 913 } // namespace vixl 914 915 #endif // VIXL_AARCH32_OPERANDS_AARCH32_H_ 916