Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/vixl/src/aarch32/operands-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
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
extern "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
46
namespace vixl {
47
namespace aarch32 {
48
49
// Operand
50
51
std::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
74
std::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
100
std::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
109
std::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
118
std::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
126
ImmediateVbic::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
156
DataType 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
174
NeonImmediate 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
195
ImmediateVmov::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
295
DataType 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
320
NeonImmediate 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
362
ImmediateVmvn::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
403
DataType 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
423
NeonImmediate 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
448
ImmediateVorr::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
478
DataType 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
496
NeonImmediate 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
518
std::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
550
std::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
565