1// Copyright 2016, 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 notice,
10//     this list of conditions and the following disclaimer in the documentation
11//     and/or other materials provided with the distribution.
12//   * Neither the name of ARM Limited nor the names of its contributors may be
13//     used to endorse or promote products derived from this software without
14//     specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#include "operands-aarch64.h"
28
29namespace vixl {
30namespace aarch64 {
31
32// CPURegList utilities.
33CPURegister CPURegList::PopLowestIndex() {
34  if (IsEmpty()) {
35    return NoCPUReg;
36  }
37  int index = CountTrailingZeros(list_);
38  VIXL_ASSERT((1 << index) & list_);
39  Remove(index);
40  return CPURegister(index, size_, type_);
41}
42
43
44CPURegister CPURegList::PopHighestIndex() {
45  VIXL_ASSERT(IsValid());
46  if (IsEmpty()) {
47    return NoCPUReg;
48  }
49  int index = CountLeadingZeros(list_);
50  index = kRegListSizeInBits - 1 - index;
51  VIXL_ASSERT((1 << index) & list_);
52  Remove(index);
53  return CPURegister(index, size_, type_);
54}
55
56
57bool CPURegList::IsValid() const {
58  if ((type_ == CPURegister::kRegister) || (type_ == CPURegister::kVRegister)) {
59    bool is_valid = true;
60    // Try to create a CPURegister for each element in the list.
61    for (int i = 0; i < kRegListSizeInBits; i++) {
62      if (((list_ >> i) & 1) != 0) {
63        is_valid &= CPURegister(i, size_, type_).IsValid();
64      }
65    }
66    return is_valid;
67  } else if (type_ == CPURegister::kNoRegister) {
68    // We can't use IsEmpty here because that asserts IsValid().
69    return list_ == 0;
70  } else {
71    return false;
72  }
73}
74
75
76void CPURegList::RemoveCalleeSaved() {
77  if (GetType() == CPURegister::kRegister) {
78    Remove(GetCalleeSaved(GetRegisterSizeInBits()));
79  } else if (GetType() == CPURegister::kVRegister) {
80    Remove(GetCalleeSavedV(GetRegisterSizeInBits()));
81  } else {
82    VIXL_ASSERT(GetType() == CPURegister::kNoRegister);
83    VIXL_ASSERT(IsEmpty());
84    // The list must already be empty, so do nothing.
85  }
86}
87
88
89CPURegList CPURegList::Union(const CPURegList& list_1,
90                             const CPURegList& list_2,
91                             const CPURegList& list_3) {
92  return Union(list_1, Union(list_2, list_3));
93}
94
95
96CPURegList CPURegList::Union(const CPURegList& list_1,
97                             const CPURegList& list_2,
98                             const CPURegList& list_3,
99                             const CPURegList& list_4) {
100  return Union(Union(list_1, list_2), Union(list_3, list_4));
101}
102
103
104CPURegList CPURegList::Intersection(const CPURegList& list_1,
105                                    const CPURegList& list_2,
106                                    const CPURegList& list_3) {
107  return Intersection(list_1, Intersection(list_2, list_3));
108}
109
110
111CPURegList CPURegList::Intersection(const CPURegList& list_1,
112                                    const CPURegList& list_2,
113                                    const CPURegList& list_3,
114                                    const CPURegList& list_4) {
115  return Intersection(Intersection(list_1, list_2),
116                      Intersection(list_3, list_4));
117}
118
119
120CPURegList CPURegList::GetCalleeSaved(unsigned size) {
121  return CPURegList(CPURegister::kRegister, size, 19, 29);
122}
123
124
125CPURegList CPURegList::GetCalleeSavedV(unsigned size) {
126  return CPURegList(CPURegister::kVRegister, size, 8, 15);
127}
128
129
130CPURegList CPURegList::GetCallerSaved(unsigned size) {
131  // Registers x0-x18 and lr (x30) are caller-saved.
132  CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18);
133  // Do not use lr directly to avoid initialisation order fiasco bugs for users.
134  list.Combine(Register(30, kXRegSize));
135  return list;
136}
137
138
139CPURegList CPURegList::GetCallerSavedV(unsigned size) {
140  // Registers d0-d7 and d16-d31 are caller-saved.
141  CPURegList list = CPURegList(CPURegister::kVRegister, size, 0, 7);
142  list.Combine(CPURegList(CPURegister::kVRegister, size, 16, 31));
143  return list;
144}
145
146
147const CPURegList kCalleeSaved = CPURegList::GetCalleeSaved();
148const CPURegList kCalleeSavedV = CPURegList::GetCalleeSavedV();
149const CPURegList kCallerSaved = CPURegList::GetCallerSaved();
150const CPURegList kCallerSavedV = CPURegList::GetCallerSavedV();
151
152
153// Registers.
154#define WREG(n) w##n,
155const Register Register::wregisters[] = {AARCH64_REGISTER_CODE_LIST(WREG)};
156#undef WREG
157
158#define XREG(n) x##n,
159const Register Register::xregisters[] = {AARCH64_REGISTER_CODE_LIST(XREG)};
160#undef XREG
161
162#define BREG(n) b##n,
163const VRegister VRegister::bregisters[] = {AARCH64_REGISTER_CODE_LIST(BREG)};
164#undef BREG
165
166#define HREG(n) h##n,
167const VRegister VRegister::hregisters[] = {AARCH64_REGISTER_CODE_LIST(HREG)};
168#undef HREG
169
170#define SREG(n) s##n,
171const VRegister VRegister::sregisters[] = {AARCH64_REGISTER_CODE_LIST(SREG)};
172#undef SREG
173
174#define DREG(n) d##n,
175const VRegister VRegister::dregisters[] = {AARCH64_REGISTER_CODE_LIST(DREG)};
176#undef DREG
177
178#define QREG(n) q##n,
179const VRegister VRegister::qregisters[] = {AARCH64_REGISTER_CODE_LIST(QREG)};
180#undef QREG
181
182#define VREG(n) v##n,
183const VRegister VRegister::vregisters[] = {AARCH64_REGISTER_CODE_LIST(VREG)};
184#undef VREG
185
186
187const Register& Register::GetWRegFromCode(unsigned code) {
188  if (code == kSPRegInternalCode) {
189    return wsp;
190  } else {
191    VIXL_ASSERT(code < kNumberOfRegisters);
192    return wregisters[code];
193  }
194}
195
196
197const Register& Register::GetXRegFromCode(unsigned code) {
198  if (code == kSPRegInternalCode) {
199    return sp;
200  } else {
201    VIXL_ASSERT(code < kNumberOfRegisters);
202    return xregisters[code];
203  }
204}
205
206
207const VRegister& VRegister::GetBRegFromCode(unsigned code) {
208  VIXL_ASSERT(code < kNumberOfVRegisters);
209  return bregisters[code];
210}
211
212
213const VRegister& VRegister::GetHRegFromCode(unsigned code) {
214  VIXL_ASSERT(code < kNumberOfVRegisters);
215  return hregisters[code];
216}
217
218
219const VRegister& VRegister::GetSRegFromCode(unsigned code) {
220  VIXL_ASSERT(code < kNumberOfVRegisters);
221  return sregisters[code];
222}
223
224
225const VRegister& VRegister::GetDRegFromCode(unsigned code) {
226  VIXL_ASSERT(code < kNumberOfVRegisters);
227  return dregisters[code];
228}
229
230
231const VRegister& VRegister::GetQRegFromCode(unsigned code) {
232  VIXL_ASSERT(code < kNumberOfVRegisters);
233  return qregisters[code];
234}
235
236
237const VRegister& VRegister::GetVRegFromCode(unsigned code) {
238  VIXL_ASSERT(code < kNumberOfVRegisters);
239  return vregisters[code];
240}
241
242
243const Register& CPURegister::W() const {
244  VIXL_ASSERT(IsValidRegister());
245  return Register::GetWRegFromCode(code_);
246}
247
248
249const Register& CPURegister::X() const {
250  VIXL_ASSERT(IsValidRegister());
251  return Register::GetXRegFromCode(code_);
252}
253
254
255const VRegister& CPURegister::B() const {
256  VIXL_ASSERT(IsValidVRegister());
257  return VRegister::GetBRegFromCode(code_);
258}
259
260
261const VRegister& CPURegister::H() const {
262  VIXL_ASSERT(IsValidVRegister());
263  return VRegister::GetHRegFromCode(code_);
264}
265
266
267const VRegister& CPURegister::S() const {
268  VIXL_ASSERT(IsValidVRegister());
269  return VRegister::GetSRegFromCode(code_);
270}
271
272
273const VRegister& CPURegister::D() const {
274  VIXL_ASSERT(IsValidVRegister());
275  return VRegister::GetDRegFromCode(code_);
276}
277
278
279const VRegister& CPURegister::Q() const {
280  VIXL_ASSERT(IsValidVRegister());
281  return VRegister::GetQRegFromCode(code_);
282}
283
284
285const VRegister& CPURegister::V() const {
286  VIXL_ASSERT(IsValidVRegister());
287  return VRegister::GetVRegFromCode(code_);
288}
289
290
291// Operand.
292Operand::Operand(int64_t immediate)
293    : immediate_(immediate),
294      reg_(NoReg),
295      shift_(NO_SHIFT),
296      extend_(NO_EXTEND),
297      shift_amount_(0) {}
298
299
300Operand::Operand(Register reg, Shift shift, unsigned shift_amount)
301    : reg_(reg),
302      shift_(shift),
303      extend_(NO_EXTEND),
304      shift_amount_(shift_amount) {
305  VIXL_ASSERT(shift != MSL);
306  VIXL_ASSERT(reg.Is64Bits() || (shift_amount < kWRegSize));
307  VIXL_ASSERT(reg.Is32Bits() || (shift_amount < kXRegSize));
308  VIXL_ASSERT(!reg.IsSP());
309}
310
311
312Operand::Operand(Register reg, Extend extend, unsigned shift_amount)
313    : reg_(reg),
314      shift_(NO_SHIFT),
315      extend_(extend),
316      shift_amount_(shift_amount) {
317  VIXL_ASSERT(reg.IsValid());
318  VIXL_ASSERT(shift_amount <= 4);
319  VIXL_ASSERT(!reg.IsSP());
320
321  // Extend modes SXTX and UXTX require a 64-bit register.
322  VIXL_ASSERT(reg.Is64Bits() || ((extend != SXTX) && (extend != UXTX)));
323}
324
325
326bool Operand::IsImmediate() const { return reg_.Is(NoReg); }
327
328
329bool Operand::IsPlainRegister() const {
330  return reg_.IsValid() &&
331         (((shift_ == NO_SHIFT) && (extend_ == NO_EXTEND)) ||
332          // No-op shifts.
333          ((shift_ != NO_SHIFT) && (shift_amount_ == 0)) ||
334          // No-op extend operations.
335          // We can't include [US]XTW here without knowing more about the
336          // context; they are only no-ops for 32-bit operations.
337          //
338          // For example, this operand could be replaced with w1:
339          //   __ Add(w0, w0, Operand(w1, UXTW));
340          // However, no plain register can replace it in this context:
341          //   __ Add(x0, x0, Operand(w1, UXTW));
342          (((extend_ == UXTX) || (extend_ == SXTX)) && (shift_amount_ == 0)));
343}
344
345
346bool Operand::IsShiftedRegister() const {
347  return reg_.IsValid() && (shift_ != NO_SHIFT);
348}
349
350
351bool Operand::IsExtendedRegister() const {
352  return reg_.IsValid() && (extend_ != NO_EXTEND);
353}
354
355
356bool Operand::IsZero() const {
357  if (IsImmediate()) {
358    return GetImmediate() == 0;
359  } else {
360    return GetRegister().IsZero();
361  }
362}
363
364
365Operand Operand::ToExtendedRegister() const {
366  VIXL_ASSERT(IsShiftedRegister());
367  VIXL_ASSERT((shift_ == LSL) && (shift_amount_ <= 4));
368  return Operand(reg_, reg_.Is64Bits() ? UXTX : UXTW, shift_amount_);
369}
370
371
372// MemOperand
373MemOperand::MemOperand()
374    : base_(NoReg),
375      regoffset_(NoReg),
376      offset_(0),
377      addrmode_(Offset),
378      shift_(NO_SHIFT),
379      extend_(NO_EXTEND) {}
380
381
382MemOperand::MemOperand(Register base, int64_t offset, AddrMode addrmode)
383    : base_(base),
384      regoffset_(NoReg),
385      offset_(offset),
386      addrmode_(addrmode),
387      shift_(NO_SHIFT),
388      extend_(NO_EXTEND),
389      shift_amount_(0) {
390  VIXL_ASSERT(base.Is64Bits() && !base.IsZero());
391}
392
393
394MemOperand::MemOperand(Register base,
395                       Register regoffset,
396                       Extend extend,
397                       unsigned shift_amount)
398    : base_(base),
399      regoffset_(regoffset),
400      offset_(0),
401      addrmode_(Offset),
402      shift_(NO_SHIFT),
403      extend_(extend),
404      shift_amount_(shift_amount) {
405  VIXL_ASSERT(base.Is64Bits() && !base.IsZero());
406  VIXL_ASSERT(!regoffset.IsSP());
407  VIXL_ASSERT((extend == UXTW) || (extend == SXTW) || (extend == SXTX));
408
409  // SXTX extend mode requires a 64-bit offset register.
410  VIXL_ASSERT(regoffset.Is64Bits() || (extend != SXTX));
411}
412
413
414MemOperand::MemOperand(Register base,
415                       Register regoffset,
416                       Shift shift,
417                       unsigned shift_amount)
418    : base_(base),
419      regoffset_(regoffset),
420      offset_(0),
421      addrmode_(Offset),
422      shift_(shift),
423      extend_(NO_EXTEND),
424      shift_amount_(shift_amount) {
425  VIXL_ASSERT(base.Is64Bits() && !base.IsZero());
426  VIXL_ASSERT(regoffset.Is64Bits() && !regoffset.IsSP());
427  VIXL_ASSERT(shift == LSL);
428}
429
430
431MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode)
432    : base_(base),
433      regoffset_(NoReg),
434      addrmode_(addrmode),
435      shift_(NO_SHIFT),
436      extend_(NO_EXTEND),
437      shift_amount_(0) {
438  VIXL_ASSERT(base.Is64Bits() && !base.IsZero());
439
440  if (offset.IsImmediate()) {
441    offset_ = offset.GetImmediate();
442  } else if (offset.IsShiftedRegister()) {
443    VIXL_ASSERT((addrmode == Offset) || (addrmode == PostIndex));
444
445    regoffset_ = offset.GetRegister();
446    shift_ = offset.GetShift();
447    shift_amount_ = offset.GetShiftAmount();
448
449    extend_ = NO_EXTEND;
450    offset_ = 0;
451
452    // These assertions match those in the shifted-register constructor.
453    VIXL_ASSERT(regoffset_.Is64Bits() && !regoffset_.IsSP());
454    VIXL_ASSERT(shift_ == LSL);
455  } else {
456    VIXL_ASSERT(offset.IsExtendedRegister());
457    VIXL_ASSERT(addrmode == Offset);
458
459    regoffset_ = offset.GetRegister();
460    extend_ = offset.GetExtend();
461    shift_amount_ = offset.GetShiftAmount();
462
463    shift_ = NO_SHIFT;
464    offset_ = 0;
465
466    // These assertions match those in the extended-register constructor.
467    VIXL_ASSERT(!regoffset_.IsSP());
468    VIXL_ASSERT((extend_ == UXTW) || (extend_ == SXTW) || (extend_ == SXTX));
469    VIXL_ASSERT((regoffset_.Is64Bits() || (extend_ != SXTX)));
470  }
471}
472
473
474bool MemOperand::IsImmediateOffset() const {
475  return (addrmode_ == Offset) && regoffset_.Is(NoReg);
476}
477
478
479bool MemOperand::IsRegisterOffset() const {
480  return (addrmode_ == Offset) && !regoffset_.Is(NoReg);
481}
482
483
484bool MemOperand::IsPreIndex() const { return addrmode_ == PreIndex; }
485
486
487bool MemOperand::IsPostIndex() const { return addrmode_ == PostIndex; }
488
489
490void MemOperand::AddOffset(int64_t offset) {
491  VIXL_ASSERT(IsImmediateOffset());
492  offset_ += offset;
493}
494
495
496GenericOperand::GenericOperand(const CPURegister& reg)
497    : cpu_register_(reg), mem_op_size_(0) {
498  if (reg.IsQ()) {
499    VIXL_ASSERT(reg.GetSizeInBits() > static_cast<int>(kXRegSize));
500    // Support for Q registers is not implemented yet.
501    VIXL_UNIMPLEMENTED();
502  }
503}
504
505
506GenericOperand::GenericOperand(const MemOperand& mem_op, size_t mem_op_size)
507    : cpu_register_(NoReg), mem_op_(mem_op), mem_op_size_(mem_op_size) {
508  if (mem_op_size_ > kXRegSizeInBytes) {
509    // We only support generic operands up to the size of X registers.
510    VIXL_UNIMPLEMENTED();
511  }
512}
513
514bool GenericOperand::Equals(const GenericOperand& other) const {
515  if (!IsValid() || !other.IsValid()) {
516    // Two invalid generic operands are considered equal.
517    return !IsValid() && !other.IsValid();
518  }
519  if (IsCPURegister() && other.IsCPURegister()) {
520    return GetCPURegister().Is(other.GetCPURegister());
521  } else if (IsMemOperand() && other.IsMemOperand()) {
522    return GetMemOperand().Equals(other.GetMemOperand()) &&
523           (GetMemOperandSizeInBytes() == other.GetMemOperandSizeInBytes());
524  }
525  return false;
526}
527}
528}  // namespace vixl::aarch64
529