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
33namespace vixl {
34namespace 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//
50class 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
234std::ostream& operator<<(std::ostream& os, const Operand& operand);
235
236class 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  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>
324  bool CanConvert() const {
325    return CanConvert(DataTypeIdentity<T>());
326  }
327
328  template <typename 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  }
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  }
342  bool CanConvert(const DataTypeIdentity<uint64_t>&) const {
343    return IsInteger() || CanConvert<uint32_t>();
344  }
345  bool CanConvert(const DataTypeIdentity<float>&) const {
346    return IsFloat() || IsDouble();
347  }
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_;
360    NeonImmediateType(uint64_t u) : u64_(u) {}
361    NeonImmediateType(int64_t u) : u64_(u) {}
362    NeonImmediateType(uint32_t u) : u32_(u) {}
363    NeonImmediateType(int32_t u) : u32_(u) {}
364    NeonImmediateType(double d) : d_(d) {}
365    NeonImmediateType(float f) : f_(f) {}
366    NeonImmediateType(const NeonImmediateType& ref) : u64_(ref.u64_) {}
367  } imm_;
368
369  DataType immediate_type_;
370};
371
372std::ostream& operator<<(std::ostream& os, const NeonImmediate& operand);
373
374class NeonOperand {
375 public:
376  NeonOperand(int32_t immediate)  // NOLINT(runtime/explicit)
377      : imm_(immediate),
378        rm_(NoDReg) {}
379  NeonOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
380      : imm_(immediate),
381        rm_(NoDReg) {}
382  NeonOperand(int64_t immediate)  // NOLINT(runtime/explicit)
383      : imm_(immediate),
384        rm_(NoDReg) {}
385  NeonOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
386      : imm_(immediate),
387        rm_(NoDReg) {}
388  NeonOperand(float immediate)  // NOLINT(runtime/explicit)
389      : imm_(immediate),
390        rm_(NoDReg) {}
391  NeonOperand(double immediate)  // NOLINT(runtime/explicit)
392      : imm_(immediate),
393        rm_(NoDReg) {}
394  NeonOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
395      : imm_(imm),
396        rm_(NoDReg) {}
397  NeonOperand(const VRegister& rm)  // NOLINT(runtime/explicit)
398      : imm_(0),
399        rm_(rm) {
400    VIXL_ASSERT(rm_.IsValid());
401  }
402
403  bool IsImmediate() const { return !rm_.IsValid(); }
404  bool IsRegister() const { return rm_.IsValid(); }
405  bool IsFloatZero() const {
406    VIXL_ASSERT(IsImmediate());
407    return imm_.IsFloatZero();
408  }
409
410  const NeonImmediate& GetNeonImmediate() const { return imm_; }
411
412  VRegister GetRegister() const {
413    VIXL_ASSERT(IsRegister());
414    return rm_;
415  }
416
417 protected:
418  NeonImmediate imm_;
419  VRegister rm_;
420};
421
422std::ostream& operator<<(std::ostream& os, const NeonOperand& operand);
423
424// SOperand represents either an immediate or a SRegister.
425class 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.
431  SOperand(int32_t immediate)  // NOLINT(runtime/explicit)
432      : NeonOperand(immediate) {}
433  SOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
434      : NeonOperand(immediate) {}
435  // #<immediate>
436  // where <immediate> is 32bit float
437  SOperand(float immediate)  // NOLINT(runtime/explicit)
438      : NeonOperand(immediate) {}
439  // where <immediate> is 64bit float
440  SOperand(double immediate)  // NOLINT(runtime/explicit)
441      : NeonOperand(immediate) {}
442
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.
449  SOperand(SRegister rm)  // NOLINT(runtime/explicit)
450      : NeonOperand(rm) {}
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.
458std::ostream& operator<<(std::ostream& os, const SOperand& operand);
459
460class 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.
466  DOperand(int32_t immediate)  // NOLINT(runtime/explicit)
467      : NeonOperand(immediate) {}
468  DOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
469      : NeonOperand(immediate) {}
470  DOperand(int64_t immediate)  // NOLINT(runtime/explicit)
471      : NeonOperand(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.
480  DOperand(float immediate)  // NOLINT(runtime/explicit)
481      : NeonOperand(immediate) {}
482  DOperand(double immediate)  // NOLINT(runtime/explicit)
483      : NeonOperand(immediate) {}
484
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.
490  DOperand(DRegister rm)  // NOLINT(runtime/explicit)
491      : NeonOperand(rm) {}
492
493  DRegister GetRegister() const {
494    VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kDRegister));
495    return DRegister(rm_.GetCode());
496  }
497};
498
499std::ostream& operator<<(std::ostream& os, const DOperand& operand);
500
501// QOperand represents either an immediate or a QRegister.
502class 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.
508  QOperand(int32_t immediate)  // NOLINT(runtime/explicit)
509      : NeonOperand(immediate) {}
510  QOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
511      : NeonOperand(immediate) {}
512  QOperand(int64_t immediate)  // NOLINT(runtime/explicit)
513      : NeonOperand(immediate) {}
514  QOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
515      : NeonOperand(immediate) {}
516  QOperand(float immediate)  // NOLINT(runtime/explicit)
517      : NeonOperand(immediate) {}
518  QOperand(double immediate)  // NOLINT(runtime/explicit)
519      : NeonOperand(immediate) {}
520
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.
527  QOperand(QRegister rm)  // NOLINT(runtime/explicit)
528      : NeonOperand(rm) {
529    VIXL_ASSERT(rm_.IsValid());
530  }
531
532  QRegister GetRegister() const {
533    VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kQRegister));
534    return QRegister(rm_.GetCode());
535  }
536};
537
538std::ostream& operator<<(std::ostream& os, const QOperand& operand);
539
540class ImmediateVFP : public EncodingValue {
541  template <typename T>
542  struct FloatType {
543    typedef T base_type;
544  };
545
546 public:
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>
562  static T Decode(uint32_t v) {
563    return Decode(v, FloatType<T>());
564  }
565
566  static float Decode(uint32_t imm8, const FloatType<float>&) {
567    return VFP::Imm8ToFP32(imm8);
568  }
569
570  static double Decode(uint32_t imm8, const FloatType<double>&) {
571    return VFP::Imm8ToFP64(imm8);
572  }
573};
574
575
576class 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
583class ImmediateVand : public ImmediateVbic {
584 public:
585  ImmediateVand(DataType dt, const NeonImmediate neon_imm)
586      : ImmediateVbic(dt, neon_imm) {
587    if (IsValid()) {
588      SetEncodedImmediate(~GetEncodedImmediate() & 0xff);
589    }
590  }
591};
592
593class 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
600class 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
607class 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
614class ImmediateVorn : public ImmediateVorr {
615 public:
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_.
659class MemOperand {
660 public:
661  // rn
662  // where rn is the general purpose base register only
663  explicit MemOperand(Register rn, AddrMode addrmode = Offset)
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)
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)
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)
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)
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)
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)
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)
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)
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
813  Register GetBaseRegister() const { return rn_; }
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  }
821  Sign GetSign() const { return sign_; }
822  Register GetOffsetRegister() const { return rm_; }
823  Shift GetShift() const { return shift_; }
824  unsigned GetShiftAmount() const { return shift_amount_; }
825  AddrMode GetAddrMode() const {
826    return static_cast<AddrMode>(addrmode_ & kMemOperandAddrModeMask);
827  }
828  bool IsRegisterOnly() const {
829    return (addrmode_ & kMemOperandRegisterOnly) != 0;
830  }
831
832  bool IsImmediate() const { return !rm_.IsValid(); }
833  bool IsImmediateZero() const { return !rm_.IsValid() && (offset_ == 0); }
834  bool IsPlainRegister() const {
835    return rm_.IsValid() && shift_.IsLSL() && (shift_amount_ == 0);
836  }
837  bool IsShiftedRegister() const { return rm_.IsValid(); }
838  bool IsImmediateOffset() const {
839    return (GetAddrMode() == Offset) && !rm_.IsValid();
840  }
841  bool IsImmediateZeroOffset() const {
842    return (GetAddrMode() == Offset) && !rm_.IsValid() && (offset_ == 0);
843  }
844  bool IsRegisterOffset() const {
845    return (GetAddrMode() == Offset) && rm_.IsValid() && shift_.IsLSL() &&
846           (shift_amount_ == 0);
847  }
848  bool IsShiftedRegisterOffset() const {
849    return (GetAddrMode() == Offset) && rm_.IsValid();
850  }
851  uint32_t GetTypeEncodingValue() const {
852    return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue();
853  }
854  bool IsOffset() const { return GetAddrMode() == Offset; }
855  bool IsPreIndex() const { return GetAddrMode() == PreIndex; }
856  bool IsPostIndex() const { return GetAddrMode() == PostIndex; }
857  bool IsShiftValid() const { return shift_.IsValidAmount(shift_amount_); }
858
859 private:
860  static const int kMemOperandRegisterOnly = 0x1000;
861  static const int kMemOperandAddrModeMask = 0xfff;
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
899std::ostream& operator<<(std::ostream& os, const MemOperand& operand);
900
901class AlignedMemOperand : public MemOperand {
902 public:
903  AlignedMemOperand(Register rn, Alignment align, AddrMode addrmode = Offset)
904      : MemOperand(rn, addrmode), align_(align) {
905    VIXL_ASSERT(addrmode != PreIndex);
906  }
907
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
916  Alignment GetAlignment() const { return align_; }
917
918 private:
919  Alignment align_;
920};
921
922std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand);
923
924}  // namespace aarch32
925}  // namespace vixl
926
927#endif  // VIXL_AARCH32_OPERANDS_AARCH32_H_
928