Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/vixl/src/aarch32/instructions-aarch32.cc
4261 views
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 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
extern "C" {
28
#include <stdint.h>
29
}
30
31
#include <cassert>
32
#include <cstdio>
33
#include <cstdlib>
34
#include <cstring>
35
#include <iostream>
36
37
#include "utils-vixl.h"
38
#include "aarch32/constants-aarch32.h"
39
#include "aarch32/instructions-aarch32.h"
40
41
namespace vixl {
42
namespace aarch32 {
43
44
45
bool Shift::IsValidAmount(uint32_t amount) const {
46
switch (GetType()) {
47
case LSL:
48
return amount <= 31;
49
case ROR:
50
return (amount > 0) && (amount <= 31);
51
case LSR:
52
case ASR:
53
return (amount > 0) && (amount <= 32);
54
case RRX:
55
return amount == 0;
56
default:
57
VIXL_UNREACHABLE();
58
return false;
59
}
60
}
61
62
63
std::ostream& operator<<(std::ostream& os, const Register reg) {
64
switch (reg.GetCode()) {
65
case 12:
66
return os << "ip";
67
case 13:
68
return os << "sp";
69
case 14:
70
return os << "lr";
71
case 15:
72
return os << "pc";
73
default:
74
return os << "r" << reg.GetCode();
75
}
76
}
77
78
79
SRegister VRegister::S() const {
80
VIXL_ASSERT(GetType() == kSRegister);
81
return SRegister(GetCode());
82
}
83
84
85
DRegister VRegister::D() const {
86
VIXL_ASSERT(GetType() == kDRegister);
87
return DRegister(GetCode());
88
}
89
90
91
QRegister VRegister::Q() const {
92
VIXL_ASSERT(GetType() == kQRegister);
93
return QRegister(GetCode());
94
}
95
96
97
Register RegisterList::GetFirstAvailableRegister() const {
98
if (list_ == 0) {
99
return Register();
100
}
101
return Register(CountTrailingZeros(list_));
102
}
103
104
105
std::ostream& PrintRegisterList(std::ostream& os, // NOLINT(runtime/references)
106
uint32_t list) {
107
os << "{";
108
bool first = true;
109
int code = 0;
110
while (list != 0) {
111
if ((list & 1) != 0) {
112
if (first) {
113
first = false;
114
} else {
115
os << ",";
116
}
117
os << Register(code);
118
}
119
list >>= 1;
120
code++;
121
}
122
os << "}";
123
return os;
124
}
125
126
127
std::ostream& operator<<(std::ostream& os, RegisterList registers) {
128
return PrintRegisterList(os, registers.GetList());
129
}
130
131
132
QRegister VRegisterList::GetFirstAvailableQRegister() const {
133
for (uint32_t i = 0; i < kNumberOfQRegisters; i++) {
134
if (((list_ >> (i * 4)) & 0xf) == 0xf) return QRegister(i);
135
}
136
return QRegister();
137
}
138
139
140
DRegister VRegisterList::GetFirstAvailableDRegister() const {
141
for (uint32_t i = 0; i < kMaxNumberOfDRegisters; i++) {
142
if (((list_ >> (i * 2)) & 0x3) == 0x3) return DRegister(i);
143
}
144
return DRegister();
145
}
146
147
148
SRegister VRegisterList::GetFirstAvailableSRegister() const {
149
for (uint32_t i = 0; i < kNumberOfSRegisters; i++) {
150
if (((list_ >> i) & 0x1) != 0) return SRegister(i);
151
}
152
return SRegister();
153
}
154
155
156
std::ostream& operator<<(std::ostream& os, SRegisterList reglist) {
157
SRegister first = reglist.GetFirstSRegister();
158
SRegister last = reglist.GetLastSRegister();
159
if (first.Is(last))
160
os << "{" << first << "}";
161
else
162
os << "{" << first << "-" << last << "}";
163
return os;
164
}
165
166
167
std::ostream& operator<<(std::ostream& os, DRegisterList reglist) {
168
DRegister first = reglist.GetFirstDRegister();
169
DRegister last = reglist.GetLastDRegister();
170
if (first.Is(last))
171
os << "{" << first << "}";
172
else
173
os << "{" << first << "-" << last << "}";
174
return os;
175
}
176
177
std::ostream& operator<<(std::ostream& os, NeonRegisterList nreglist) {
178
DRegister first = nreglist.GetFirstDRegister();
179
int increment = nreglist.IsSingleSpaced() ? 1 : 2;
180
int count =
181
nreglist.GetLastDRegister().GetCode() - first.GetCode() + increment;
182
if (count < 0) count += kMaxNumberOfDRegisters;
183
os << "{";
184
bool first_displayed = false;
185
for (;;) {
186
if (first_displayed) {
187
os << ",";
188
} else {
189
first_displayed = true;
190
}
191
os << first;
192
if (nreglist.IsTransferOneLane()) {
193
os << "[" << nreglist.GetTransferLane() << "]";
194
} else if (nreglist.IsTransferAllLanes()) {
195
os << "[]";
196
}
197
count -= increment;
198
if (count <= 0) break;
199
unsigned next = first.GetCode() + increment;
200
if (next >= kMaxNumberOfDRegisters) next -= kMaxNumberOfDRegisters;
201
first = DRegister(next);
202
}
203
os << "}";
204
return os;
205
}
206
207
208
const char* SpecialRegister::GetName() const {
209
switch (reg_) {
210
case APSR:
211
return "APSR";
212
case SPSR:
213
return "SPSR";
214
}
215
VIXL_UNREACHABLE();
216
return "??";
217
}
218
219
220
const char* MaskedSpecialRegister::GetName() const {
221
switch (reg_) {
222
case APSR_nzcvq:
223
return "APSR_nzcvq";
224
case APSR_g:
225
return "APSR_g";
226
case APSR_nzcvqg:
227
return "APSR_nzcvqg";
228
case CPSR_c:
229
return "CPSR_c";
230
case CPSR_x:
231
return "CPSR_x";
232
case CPSR_xc:
233
return "CPSR_xc";
234
case CPSR_sc:
235
return "CPSR_sc";
236
case CPSR_sx:
237
return "CPSR_sx";
238
case CPSR_sxc:
239
return "CPSR_sxc";
240
case CPSR_fc:
241
return "CPSR_fc";
242
case CPSR_fx:
243
return "CPSR_fx";
244
case CPSR_fxc:
245
return "CPSR_fxc";
246
case CPSR_fsc:
247
return "CPSR_fsc";
248
case CPSR_fsx:
249
return "CPSR_fsx";
250
case CPSR_fsxc:
251
return "CPSR_fsxc";
252
case SPSR_c:
253
return "SPSR_c";
254
case SPSR_x:
255
return "SPSR_x";
256
case SPSR_xc:
257
return "SPSR_xc";
258
case SPSR_s:
259
return "SPSR_s";
260
case SPSR_sc:
261
return "SPSR_sc";
262
case SPSR_sx:
263
return "SPSR_sx";
264
case SPSR_sxc:
265
return "SPSR_sxc";
266
case SPSR_f:
267
return "SPSR_f";
268
case SPSR_fc:
269
return "SPSR_fc";
270
case SPSR_fx:
271
return "SPSR_fx";
272
case SPSR_fxc:
273
return "SPSR_fxc";
274
case SPSR_fs:
275
return "SPSR_fs";
276
case SPSR_fsc:
277
return "SPSR_fsc";
278
case SPSR_fsx:
279
return "SPSR_fsx";
280
case SPSR_fsxc:
281
return "SPSR_fsxc";
282
}
283
VIXL_UNREACHABLE();
284
return "??";
285
}
286
287
288
const char* BankedRegister::GetName() const {
289
switch (reg_) {
290
case R8_usr:
291
return "R8_usr";
292
case R9_usr:
293
return "R9_usr";
294
case R10_usr:
295
return "R10_usr";
296
case R11_usr:
297
return "R11_usr";
298
case R12_usr:
299
return "R12_usr";
300
case SP_usr:
301
return "SP_usr";
302
case LR_usr:
303
return "LR_usr";
304
case R8_fiq:
305
return "R8_fiq";
306
case R9_fiq:
307
return "R9_fiq";
308
case R10_fiq:
309
return "R10_fiq";
310
case R11_fiq:
311
return "R11_fiq";
312
case R12_fiq:
313
return "R12_fiq";
314
case SP_fiq:
315
return "SP_fiq";
316
case LR_fiq:
317
return "LR_fiq";
318
case LR_irq:
319
return "LR_irq";
320
case SP_irq:
321
return "SP_irq";
322
case LR_svc:
323
return "LR_svc";
324
case SP_svc:
325
return "SP_svc";
326
case LR_abt:
327
return "LR_abt";
328
case SP_abt:
329
return "SP_abt";
330
case LR_und:
331
return "LR_und";
332
case SP_und:
333
return "SP_und";
334
case LR_mon:
335
return "LR_mon";
336
case SP_mon:
337
return "SP_mon";
338
case ELR_hyp:
339
return "ELR_hyp";
340
case SP_hyp:
341
return "SP_hyp";
342
case SPSR_fiq:
343
return "SPSR_fiq";
344
case SPSR_irq:
345
return "SPSR_irq";
346
case SPSR_svc:
347
return "SPSR_svc";
348
case SPSR_abt:
349
return "SPSR_abt";
350
case SPSR_und:
351
return "SPSR_und";
352
case SPSR_mon:
353
return "SPSR_mon";
354
case SPSR_hyp:
355
return "SPSR_hyp";
356
}
357
VIXL_UNREACHABLE();
358
return "??";
359
}
360
361
const char* SpecialFPRegister::GetName() const {
362
switch (reg_) {
363
case FPSID:
364
return "FPSID";
365
case FPSCR:
366
return "FPSCR";
367
case MVFR2:
368
return "MVFR2";
369
case MVFR1:
370
return "MVFR1";
371
case MVFR0:
372
return "MVFR0";
373
case FPEXC:
374
return "FPEXC";
375
}
376
VIXL_UNREACHABLE();
377
return "??";
378
}
379
380
381
const char* Condition::GetName() const {
382
switch (condition_) {
383
case eq:
384
return "eq";
385
case ne:
386
return "ne";
387
case cs:
388
return "cs";
389
case cc:
390
return "cc";
391
case mi:
392
return "mi";
393
case pl:
394
return "pl";
395
case vs:
396
return "vs";
397
case vc:
398
return "vc";
399
case hi:
400
return "hi";
401
case ls:
402
return "ls";
403
case ge:
404
return "ge";
405
case lt:
406
return "lt";
407
case gt:
408
return "gt";
409
case le:
410
return "le";
411
case al:
412
return "";
413
case Condition::kNone:
414
return "";
415
}
416
return "<und>";
417
}
418
419
420
const char* Shift::GetName() const {
421
switch (shift_) {
422
case LSL:
423
return "lsl";
424
case LSR:
425
return "lsr";
426
case ASR:
427
return "asr";
428
case ROR:
429
return "ror";
430
case RRX:
431
return "rrx";
432
}
433
VIXL_UNREACHABLE();
434
return "??";
435
}
436
437
438
const char* EncodingSize::GetName() const {
439
switch (size_) {
440
case Best:
441
case Narrow:
442
return "";
443
case Wide:
444
return ".w";
445
}
446
VIXL_UNREACHABLE();
447
return "??";
448
}
449
450
451
const char* DataType::GetName() const {
452
switch (value_) {
453
case kDataTypeValueInvalid:
454
return ".??";
455
case kDataTypeValueNone:
456
return "";
457
case S8:
458
return ".s8";
459
case S16:
460
return ".s16";
461
case S32:
462
return ".s32";
463
case S64:
464
return ".s64";
465
case U8:
466
return ".u8";
467
case U16:
468
return ".u16";
469
case U32:
470
return ".u32";
471
case U64:
472
return ".u64";
473
case F16:
474
return ".f16";
475
case F32:
476
return ".f32";
477
case F64:
478
return ".f64";
479
case I8:
480
return ".i8";
481
case I16:
482
return ".i16";
483
case I32:
484
return ".i32";
485
case I64:
486
return ".i64";
487
case P8:
488
return ".p8";
489
case P64:
490
return ".p64";
491
case Untyped8:
492
return ".8";
493
case Untyped16:
494
return ".16";
495
case Untyped32:
496
return ".32";
497
case Untyped64:
498
return ".64";
499
}
500
VIXL_UNREACHABLE();
501
return ".??";
502
}
503
504
505
const char* MemoryBarrier::GetName() const {
506
switch (type_) {
507
case OSHLD:
508
return "oshld";
509
case OSHST:
510
return "oshst";
511
case OSH:
512
return "osh";
513
case NSHLD:
514
return "nshld";
515
case NSHST:
516
return "nshst";
517
case NSH:
518
return "nsh";
519
case ISHLD:
520
return "ishld";
521
case ISHST:
522
return "ishst";
523
case ISH:
524
return "ish";
525
case LD:
526
return "ld";
527
case ST:
528
return "st";
529
case SY:
530
return "sy";
531
}
532
switch (static_cast<int>(type_)) {
533
case 0:
534
return "#0x0";
535
case 4:
536
return "#0x4";
537
case 8:
538
return "#0x8";
539
case 0xc:
540
return "#0xc";
541
}
542
VIXL_UNREACHABLE();
543
return "??";
544
}
545
546
547
const char* InterruptFlags::GetName() const {
548
switch (type_) {
549
case F:
550
return "f";
551
case I:
552
return "i";
553
case IF:
554
return "if";
555
case A:
556
return "a";
557
case AF:
558
return "af";
559
case AI:
560
return "ai";
561
case AIF:
562
return "aif";
563
}
564
VIXL_ASSERT(type_ == 0);
565
return "";
566
}
567
568
569
const char* Endianness::GetName() const {
570
switch (type_) {
571
case LE:
572
return "le";
573
case BE:
574
return "be";
575
}
576
VIXL_UNREACHABLE();
577
return "??";
578
}
579
580
581
// Constructor used for disassembly.
582
ImmediateShiftOperand::ImmediateShiftOperand(int shift_value, int amount_value)
583
: Shift(shift_value) {
584
switch (shift_value) {
585
case LSL:
586
amount_ = amount_value;
587
break;
588
case LSR:
589
case ASR:
590
amount_ = (amount_value == 0) ? 32 : amount_value;
591
break;
592
case ROR:
593
amount_ = amount_value;
594
if (amount_value == 0) SetType(RRX);
595
break;
596
default:
597
VIXL_UNREACHABLE();
598
SetType(LSL);
599
amount_ = 0;
600
break;
601
}
602
}
603
604
605
ImmediateT32::ImmediateT32(uint32_t imm) {
606
// 00000000 00000000 00000000 abcdefgh
607
if ((imm & ~0xff) == 0) {
608
SetEncodingValue(imm);
609
return;
610
}
611
if ((imm >> 16) == (imm & 0xffff)) {
612
if ((imm & 0xff00) == 0) {
613
// 00000000 abcdefgh 00000000 abcdefgh
614
SetEncodingValue((imm & 0xff) | (0x1 << 8));
615
return;
616
}
617
if ((imm & 0xff) == 0) {
618
// abcdefgh 00000000 abcdefgh 00000000
619
SetEncodingValue(((imm >> 8) & 0xff) | (0x2 << 8));
620
return;
621
}
622
if (((imm >> 8) & 0xff) == (imm & 0xff)) {
623
// abcdefgh abcdefgh abcdefgh abcdefgh
624
SetEncodingValue((imm & 0xff) | (0x3 << 8));
625
return;
626
}
627
}
628
for (int shift = 0; shift < 24; shift++) {
629
uint32_t imm8 = imm >> (24 - shift);
630
uint32_t overflow = imm << (8 + shift);
631
if ((imm8 <= 0xff) && ((imm8 & 0x80) != 0) && (overflow == 0)) {
632
SetEncodingValue(((shift + 8) << 7) | (imm8 & 0x7F));
633
return;
634
}
635
}
636
}
637
638
639
static inline uint32_t ror(uint32_t x, int i) {
640
VIXL_ASSERT((0 < i) && (i < 32));
641
return (x >> i) | (x << (32 - i));
642
}
643
644
645
bool ImmediateT32::IsImmediateT32(uint32_t imm) {
646
/* abcdefgh abcdefgh abcdefgh abcdefgh */
647
if ((imm ^ ror(imm, 8)) == 0) return true;
648
/* 00000000 abcdefgh 00000000 abcdefgh */
649
/* abcdefgh 00000000 abcdefgh 00000000 */
650
if ((imm ^ ror(imm, 16)) == 0 &&
651
(((imm & 0xff00) == 0) || ((imm & 0xff) == 0)))
652
return true;
653
/* isolate least-significant set bit */
654
uint32_t lsb = imm & UnsignedNegate(imm);
655
/* if imm is less than lsb*256 then it fits, but instead we test imm/256 to
656
* avoid overflow (underflow is always a successful case) */
657
return ((imm >> 8) < lsb);
658
}
659
660
661
uint32_t ImmediateT32::Decode(uint32_t value) {
662
uint32_t base = value & 0xff;
663
switch (value >> 8) {
664
case 0:
665
return base;
666
case 1:
667
return base | (base << 16);
668
case 2:
669
return (base << 8) | (base << 24);
670
case 3:
671
return base | (base << 8) | (base << 16) | (base << 24);
672
default:
673
base |= 0x80;
674
return base << (32 - (value >> 7));
675
}
676
}
677
678
679
ImmediateA32::ImmediateA32(uint32_t imm) {
680
// Deal with rot = 0 first to avoid undefined shift by 32.
681
if (imm <= 0xff) {
682
SetEncodingValue(imm);
683
return;
684
}
685
for (int rot = 2; rot < 32; rot += 2) {
686
uint32_t imm8 = (imm << rot) | (imm >> (32 - rot));
687
if (imm8 <= 0xff) {
688
SetEncodingValue((rot << 7) | imm8);
689
return;
690
}
691
}
692
}
693
694
695
bool ImmediateA32::IsImmediateA32(uint32_t imm) {
696
/* fast-out */
697
if (imm < 256) return true;
698
/* avoid getting confused by wrapped-around bytes (this transform has no
699
* effect on pass/fail results) */
700
if (imm & 0xff000000) imm = ror(imm, 16);
701
/* copy odd-numbered set bits into even-numbered bits immediately below, so
702
* that the least-significant set bit is always an even bit */
703
imm = imm | ((imm >> 1) & 0x55555555);
704
/* isolate least-significant set bit (always even) */
705
uint32_t lsb = imm & UnsignedNegate(imm);
706
/* if imm is less than lsb*256 then it fits, but instead we test imm/256 to
707
* avoid overflow (underflow is always a successful case) */
708
return ((imm >> 8) < lsb);
709
}
710
711
712
uint32_t ImmediateA32::Decode(uint32_t value) {
713
int rotation = (value >> 8) * 2;
714
VIXL_ASSERT(rotation >= 0);
715
VIXL_ASSERT(rotation <= 30);
716
value &= 0xff;
717
if (rotation == 0) return value;
718
return (value >> rotation) | (value << (32 - rotation));
719
}
720
721
722
uint32_t TypeEncodingValue(Shift shift) {
723
return shift.IsRRX() ? kRRXEncodedValue : shift.GetValue();
724
}
725
726
727
uint32_t AmountEncodingValue(Shift shift, uint32_t amount) {
728
switch (shift.GetType()) {
729
case LSL:
730
case ROR:
731
return amount;
732
case LSR:
733
case ASR:
734
return amount % 32;
735
case RRX:
736
return 0;
737
}
738
return 0;
739
}
740
741
} // namespace aarch32
742
} // namespace vixl
743
744