1// Copyright 2017, 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
28extern "C" {
29#include <inttypes.h>
30#include <stdint.h>
31}
32
33#include <cassert>
34#include <cmath>
35#include <cstdio>
36#include <cstdlib>
37#include <cstring>
38#include <iomanip>
39#include <iostream>
40
41#include "utils-vixl.h"
42#include "aarch32/constants-aarch32.h"
43#include "aarch32/instructions-aarch32.h"
44#include "aarch32/operands-aarch32.h"
45
46namespace vixl {
47namespace aarch32 {
48
49// Operand
50
51std::ostream& operator<<(std::ostream& os, const Operand& operand) {
52  if (operand.IsImmediate()) {
53    return os << "#" << operand.GetImmediate();
54  }
55  if (operand.IsImmediateShiftedRegister()) {
56    if ((operand.GetShift().IsLSL() || operand.GetShift().IsROR()) &&
57        (operand.GetShiftAmount() == 0)) {
58      return os << operand.GetBaseRegister();
59    }
60    if (operand.GetShift().IsRRX()) {
61      return os << operand.GetBaseRegister() << ", rrx";
62    }
63    return os << operand.GetBaseRegister() << ", " << operand.GetShift() << " #"
64              << operand.GetShiftAmount();
65  }
66  if (operand.IsRegisterShiftedRegister()) {
67    return os << operand.GetBaseRegister() << ", " << operand.GetShift() << " "
68              << operand.GetShiftRegister();
69  }
70  VIXL_UNREACHABLE();
71  return os;
72}
73
74std::ostream& operator<<(std::ostream& os, const NeonImmediate& neon_imm) {
75  if (neon_imm.IsDouble()) {
76    if (neon_imm.imm_.d_ == 0) {
77      if (copysign(1.0, neon_imm.imm_.d_) < 0.0) {
78        return os << "#-0.0";
79      }
80      return os << "#0.0";
81    }
82    return os << "#" << std::setprecision(9) << neon_imm.imm_.d_;
83  }
84  if (neon_imm.IsFloat()) {
85    if (neon_imm.imm_.f_ == 0) {
86      if (copysign(1.0, neon_imm.imm_.d_) < 0.0) return os << "#-0.0";
87      return os << "#0.0";
88    }
89    return os << "#" << std::setprecision(9) << neon_imm.imm_.f_;
90  }
91  if (neon_imm.IsInteger64()) {
92    return os << "#0x" << std::hex << std::setw(16) << std::setfill('0')
93              << neon_imm.imm_.u64_ << std::dec;
94  }
95  return os << "#" << neon_imm.imm_.u32_;
96}
97
98// SOperand
99
100std::ostream& operator<<(std::ostream& os, const SOperand& operand) {
101  if (operand.IsImmediate()) {
102    return os << operand.GetNeonImmediate();
103  }
104  return os << operand.GetRegister();
105}
106
107// DOperand
108
109std::ostream& operator<<(std::ostream& os, const DOperand& operand) {
110  if (operand.IsImmediate()) {
111    return os << operand.GetNeonImmediate();
112  }
113  return os << operand.GetRegister();
114}
115
116// QOperand
117
118std::ostream& operator<<(std::ostream& os, const QOperand& operand) {
119  if (operand.IsImmediate()) {
120    return os << operand.GetNeonImmediate();
121  }
122  return os << operand.GetRegister();
123}
124
125
126ImmediateVbic::ImmediateVbic(DataType dt, const NeonImmediate& neon_imm) {
127  if (neon_imm.IsInteger32()) {
128    uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
129    if (dt.GetValue() == I16) {
130      if ((immediate & ~0xff) == 0) {
131        SetEncodingValue(0x9);
132        SetEncodedImmediate(immediate);
133      } else if ((immediate & ~0xff00) == 0) {
134        SetEncodingValue(0xb);
135        SetEncodedImmediate(immediate >> 8);
136      }
137    } else if (dt.GetValue() == I32) {
138      if ((immediate & ~0xff) == 0) {
139        SetEncodingValue(0x1);
140        SetEncodedImmediate(immediate);
141      } else if ((immediate & ~0xff00) == 0) {
142        SetEncodingValue(0x3);
143        SetEncodedImmediate(immediate >> 8);
144      } else if ((immediate & ~0xff0000) == 0) {
145        SetEncodingValue(0x5);
146        SetEncodedImmediate(immediate >> 16);
147      } else if ((immediate & ~0xff000000) == 0) {
148        SetEncodingValue(0x7);
149        SetEncodedImmediate(immediate >> 24);
150      }
151    }
152  }
153}
154
155
156DataType ImmediateVbic::DecodeDt(uint32_t cmode) {
157  switch (cmode) {
158    case 0x1:
159    case 0x3:
160    case 0x5:
161    case 0x7:
162      return I32;
163    case 0x9:
164    case 0xb:
165      return I16;
166    default:
167      break;
168  }
169  VIXL_UNREACHABLE();
170  return kDataTypeValueInvalid;
171}
172
173
174NeonImmediate ImmediateVbic::DecodeImmediate(uint32_t cmode,
175                                             uint32_t immediate) {
176  switch (cmode) {
177    case 0x1:
178    case 0x9:
179      return immediate;
180    case 0x3:
181    case 0xb:
182      return immediate << 8;
183    case 0x5:
184      return immediate << 16;
185    case 0x7:
186      return immediate << 24;
187    default:
188      break;
189  }
190  VIXL_UNREACHABLE();
191  return 0;
192}
193
194
195ImmediateVmov::ImmediateVmov(DataType dt, const NeonImmediate& neon_imm) {
196  if (neon_imm.IsInteger()) {
197    switch (dt.GetValue()) {
198      case I8:
199        if (neon_imm.CanConvert<uint8_t>()) {
200          SetEncodingValue(0xe);
201          SetEncodedImmediate(neon_imm.GetImmediate<uint8_t>());
202        }
203        break;
204      case I16:
205        if (neon_imm.IsInteger32()) {
206          uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
207          if ((immediate & ~0xff) == 0) {
208            SetEncodingValue(0x8);
209            SetEncodedImmediate(immediate);
210          } else if ((immediate & ~0xff00) == 0) {
211            SetEncodingValue(0xa);
212            SetEncodedImmediate(immediate >> 8);
213          }
214        }
215        break;
216      case I32:
217        if (neon_imm.IsInteger32()) {
218          uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
219          if ((immediate & ~0xff) == 0) {
220            SetEncodingValue(0x0);
221            SetEncodedImmediate(immediate);
222          } else if ((immediate & ~0xff00) == 0) {
223            SetEncodingValue(0x2);
224            SetEncodedImmediate(immediate >> 8);
225          } else if ((immediate & ~0xff0000) == 0) {
226            SetEncodingValue(0x4);
227            SetEncodedImmediate(immediate >> 16);
228          } else if ((immediate & ~0xff000000) == 0) {
229            SetEncodingValue(0x6);
230            SetEncodedImmediate(immediate >> 24);
231          } else if ((immediate & ~0xff00) == 0xff) {
232            SetEncodingValue(0xc);
233            SetEncodedImmediate(immediate >> 8);
234          } else if ((immediate & ~0xff0000) == 0xffff) {
235            SetEncodingValue(0xd);
236            SetEncodedImmediate(immediate >> 16);
237          }
238        }
239        break;
240      case I64: {
241        bool is_valid = true;
242        uint32_t encoding = 0;
243        if (neon_imm.IsInteger32()) {
244          uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
245          uint32_t mask = 0xff000000;
246          for (uint32_t set_bit = 1 << 3; set_bit != 0; set_bit >>= 1) {
247            if ((immediate & mask) == mask) {
248              encoding |= set_bit;
249            } else if ((immediate & mask) != 0) {
250              is_valid = false;
251              break;
252            }
253            mask >>= 8;
254          }
255        } else {
256          uint64_t immediate = neon_imm.GetImmediate<uint64_t>();
257          uint64_t mask = UINT64_C(0xff) << 56;
258          for (uint32_t set_bit = 1 << 7; set_bit != 0; set_bit >>= 1) {
259            if ((immediate & mask) == mask) {
260              encoding |= set_bit;
261            } else if ((immediate & mask) != 0) {
262              is_valid = false;
263              break;
264            }
265            mask >>= 8;
266          }
267        }
268        if (is_valid) {
269          SetEncodingValue(0x1e);
270          SetEncodedImmediate(encoding);
271        }
272        break;
273      }
274      default:
275        break;
276    }
277  } else {
278    switch (dt.GetValue()) {
279      case F32:
280        if (neon_imm.IsFloat() || neon_imm.IsDouble()) {
281          ImmediateVFP vfp(neon_imm.GetImmediate<float>());
282          if (vfp.IsValid()) {
283            SetEncodingValue(0xf);
284            SetEncodedImmediate(vfp.GetEncodingValue());
285          }
286        }
287        break;
288      default:
289        break;
290    }
291  }
292}
293
294
295DataType ImmediateVmov::DecodeDt(uint32_t cmode) {
296  switch (cmode & 0xf) {
297    case 0x0:
298    case 0x2:
299    case 0x4:
300    case 0x6:
301    case 0xc:
302    case 0xd:
303      return I32;
304    case 0x8:
305    case 0xa:
306      return I16;
307    case 0xe:
308      return ((cmode & 0x10) == 0) ? I8 : I64;
309    case 0xf:
310      if ((cmode & 0x10) == 0) return F32;
311      break;
312    default:
313      break;
314  }
315  VIXL_UNREACHABLE();
316  return kDataTypeValueInvalid;
317}
318
319
320NeonImmediate ImmediateVmov::DecodeImmediate(uint32_t cmode,
321                                             uint32_t immediate) {
322  switch (cmode & 0xf) {
323    case 0x8:
324    case 0x0:
325      return immediate;
326    case 0x2:
327    case 0xa:
328      return immediate << 8;
329    case 0x4:
330      return immediate << 16;
331    case 0x6:
332      return immediate << 24;
333    case 0xc:
334      return (immediate << 8) | 0xff;
335    case 0xd:
336      return (immediate << 16) | 0xffff;
337    case 0xe: {
338      if (cmode == 0x1e) {
339        uint64_t encoding = 0;
340        for (uint32_t set_bit = 1 << 7; set_bit != 0; set_bit >>= 1) {
341          encoding <<= 8;
342          if ((immediate & set_bit) != 0) {
343            encoding |= 0xff;
344          }
345        }
346        return encoding;
347      } else {
348        return immediate;
349      }
350    }
351    case 0xf: {
352      return ImmediateVFP::Decode<float>(immediate);
353    }
354    default:
355      break;
356  }
357  VIXL_UNREACHABLE();
358  return 0;
359}
360
361
362ImmediateVmvn::ImmediateVmvn(DataType dt, const NeonImmediate& neon_imm) {
363  if (neon_imm.IsInteger32()) {
364    uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
365    switch (dt.GetValue()) {
366      case I16:
367        if ((immediate & ~0xff) == 0) {
368          SetEncodingValue(0x8);
369          SetEncodedImmediate(immediate);
370        } else if ((immediate & ~0xff00) == 0) {
371          SetEncodingValue(0xa);
372          SetEncodedImmediate(immediate >> 8);
373        }
374        break;
375      case I32:
376        if ((immediate & ~0xff) == 0) {
377          SetEncodingValue(0x0);
378          SetEncodedImmediate(immediate);
379        } else if ((immediate & ~0xff00) == 0) {
380          SetEncodingValue(0x2);
381          SetEncodedImmediate(immediate >> 8);
382        } else if ((immediate & ~0xff0000) == 0) {
383          SetEncodingValue(0x4);
384          SetEncodedImmediate(immediate >> 16);
385        } else if ((immediate & ~0xff000000) == 0) {
386          SetEncodingValue(0x6);
387          SetEncodedImmediate(immediate >> 24);
388        } else if ((immediate & ~0xff00) == 0xff) {
389          SetEncodingValue(0xc);
390          SetEncodedImmediate(immediate >> 8);
391        } else if ((immediate & ~0xff0000) == 0xffff) {
392          SetEncodingValue(0xd);
393          SetEncodedImmediate(immediate >> 16);
394        }
395        break;
396      default:
397        break;
398    }
399  }
400}
401
402
403DataType ImmediateVmvn::DecodeDt(uint32_t cmode) {
404  switch (cmode) {
405    case 0x0:
406    case 0x2:
407    case 0x4:
408    case 0x6:
409    case 0xc:
410    case 0xd:
411      return I32;
412    case 0x8:
413    case 0xa:
414      return I16;
415    default:
416      break;
417  }
418  VIXL_UNREACHABLE();
419  return kDataTypeValueInvalid;
420}
421
422
423NeonImmediate ImmediateVmvn::DecodeImmediate(uint32_t cmode,
424                                             uint32_t immediate) {
425  switch (cmode) {
426    case 0x0:
427    case 0x8:
428      return immediate;
429    case 0x2:
430    case 0xa:
431      return immediate << 8;
432    case 0x4:
433      return immediate << 16;
434    case 0x6:
435      return immediate << 24;
436    case 0xc:
437      return (immediate << 8) | 0xff;
438    case 0xd:
439      return (immediate << 16) | 0xffff;
440    default:
441      break;
442  }
443  VIXL_UNREACHABLE();
444  return 0;
445}
446
447
448ImmediateVorr::ImmediateVorr(DataType dt, const NeonImmediate& neon_imm) {
449  if (neon_imm.IsInteger32()) {
450    uint32_t immediate = neon_imm.GetImmediate<uint32_t>();
451    if (dt.GetValue() == I16) {
452      if ((immediate & ~0xff) == 0) {
453        SetEncodingValue(0x9);
454        SetEncodedImmediate(immediate);
455      } else if ((immediate & ~0xff00) == 0) {
456        SetEncodingValue(0xb);
457        SetEncodedImmediate(immediate >> 8);
458      }
459    } else if (dt.GetValue() == I32) {
460      if ((immediate & ~0xff) == 0) {
461        SetEncodingValue(0x1);
462        SetEncodedImmediate(immediate);
463      } else if ((immediate & ~0xff00) == 0) {
464        SetEncodingValue(0x3);
465        SetEncodedImmediate(immediate >> 8);
466      } else if ((immediate & ~0xff0000) == 0) {
467        SetEncodingValue(0x5);
468        SetEncodedImmediate(immediate >> 16);
469      } else if ((immediate & ~0xff000000) == 0) {
470        SetEncodingValue(0x7);
471        SetEncodedImmediate(immediate >> 24);
472      }
473    }
474  }
475}
476
477
478DataType ImmediateVorr::DecodeDt(uint32_t cmode) {
479  switch (cmode) {
480    case 0x1:
481    case 0x3:
482    case 0x5:
483    case 0x7:
484      return I32;
485    case 0x9:
486    case 0xb:
487      return I16;
488    default:
489      break;
490  }
491  VIXL_UNREACHABLE();
492  return kDataTypeValueInvalid;
493}
494
495
496NeonImmediate ImmediateVorr::DecodeImmediate(uint32_t cmode,
497                                             uint32_t immediate) {
498  switch (cmode) {
499    case 0x1:
500    case 0x9:
501      return immediate;
502    case 0x3:
503    case 0xb:
504      return immediate << 8;
505    case 0x5:
506      return immediate << 16;
507    case 0x7:
508      return immediate << 24;
509    default:
510      break;
511  }
512  VIXL_UNREACHABLE();
513  return 0;
514}
515
516// MemOperand
517
518std::ostream& operator<<(std::ostream& os, const MemOperand& operand) {
519  os << "[" << operand.GetBaseRegister();
520  if (operand.GetAddrMode() == PostIndex) {
521    os << "]";
522    if (operand.IsRegisterOnly()) return os << "!";
523  }
524  if (operand.IsImmediate()) {
525    if ((operand.GetOffsetImmediate() != 0) || operand.GetSign().IsMinus() ||
526        ((operand.GetAddrMode() != Offset) && !operand.IsRegisterOnly())) {
527      if (operand.GetOffsetImmediate() == 0) {
528        os << ", #" << operand.GetSign() << operand.GetOffsetImmediate();
529      } else {
530        os << ", #" << operand.GetOffsetImmediate();
531      }
532    }
533  } else if (operand.IsPlainRegister()) {
534    os << ", " << operand.GetSign() << operand.GetOffsetRegister();
535  } else if (operand.IsShiftedRegister()) {
536    os << ", " << operand.GetSign() << operand.GetOffsetRegister()
537       << ImmediateShiftOperand(operand.GetShift(), operand.GetShiftAmount());
538  } else {
539    VIXL_UNREACHABLE();
540    return os;
541  }
542  if (operand.GetAddrMode() == Offset) {
543    os << "]";
544  } else if (operand.GetAddrMode() == PreIndex) {
545    os << "]!";
546  }
547  return os;
548}
549
550std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand) {
551  os << "[" << operand.GetBaseRegister() << operand.GetAlignment() << "]";
552  if (operand.GetAddrMode() == PostIndex) {
553    if (operand.IsPlainRegister()) {
554      os << ", " << operand.GetOffsetRegister();
555    } else {
556      os << "!";
557    }
558  }
559  return os;
560}
561
562}  // namespace aarch32
563}  // namespace vixl
564