1/*
2 * Copyright (C) 2012, 2016 Apple Inc. 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. 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 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if USE(ARM64_DISASSEMBLER)
29
30#include "A64DOpcode.h"
31
32#include <stdarg.h>
33#include <stdint.h>
34#include <stdio.h>
35
36namespace JSC { namespace ARM64Disassembler {
37
38A64DOpcode::OpcodeGroup* A64DOpcode::opcodeTable[32];
39
40const char* const A64DOpcode::s_conditionNames[16] = {
41 "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
42 "hi", "ls", "ge", "lt", "gt", "le", "al", "ne"
43};
44
45const char* const A64DOpcode::s_optionName[8] = {
46 "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"
47};
48
49const char* const A64DOpcode::s_shiftNames[4] = {
50 "lsl", "lsr", "asl", "ror"
51};
52
53const char A64DOpcode::s_FPRegisterPrefix[5] = {
54 'b', 'h', 's', 'd', 'q'
55};
56
57struct OpcodeGroupInitializer {
58 unsigned m_opcodeGroupNumber;
59 uint32_t m_mask;
60 uint32_t m_pattern;
61 const char* (*m_format)(A64DOpcode*);
62};
63
64#define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
65{ groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
66
67static const OpcodeGroupInitializer opcodeGroupList[] = {
68 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair),
69 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreExclusive),
70 OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair),
71 OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister),
72 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister),
73 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister),
74 OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate),
75 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide),
76 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate),
77 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield),
78 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract),
79 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate),
80 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate),
81 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate),
82 OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration),
83 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate),
84 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate),
85 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate),
86 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint),
87 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeSystemSync),
88 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeMSRImmediate),
89 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeMSROrMRSRegister),
90 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate),
91 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister),
92 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate),
93 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate),
94 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister),
95 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate),
96 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate),
97 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset),
98 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreAuthenticated),
99 OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate),
100 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect),
101 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing1Source),
102 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source),
103 OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source),
104 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate),
105 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset),
106 OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate),
107 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare),
108 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointConditionalSelect),
109 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source),
110 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source),
111 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions),
112 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions),
113};
114
115bool A64DOpcode::s_initialized = false;
116
117void A64DOpcode::init()
118{
119 if (s_initialized)
120 return;
121
122 OpcodeGroup* lastGroups[32];
123
124 for (unsigned i = 0; i < 32; i++) {
125 opcodeTable[i] = 0;
126 lastGroups[i] = 0;
127 }
128
129 for (unsigned i = 0; i < sizeof(opcodeGroupList) / sizeof(struct OpcodeGroupInitializer); i++) {
130 OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcodeGroupList[i].m_mask, opcodeGroupList[i].m_pattern, opcodeGroupList[i].m_format);
131 uint32_t opcodeGroupNumber = opcodeGroupList[i].m_opcodeGroupNumber;
132
133 if (!opcodeTable[opcodeGroupNumber])
134 opcodeTable[opcodeGroupNumber] = newOpcodeGroup;
135 else
136 lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup);
137 lastGroups[opcodeGroupNumber] = newOpcodeGroup;
138 }
139
140 s_initialized = true;
141}
142
143void A64DOpcode::setPCAndOpcode(uint32_t* newPC, uint32_t newOpcode)
144{
145 m_currentPC = newPC;
146 m_opcode = newOpcode;
147 m_bufferOffset = 0;
148 m_formatBuffer[0] = '\0';
149}
150
151const char* A64DOpcode::disassemble(uint32_t* currentPC)
152{
153 setPCAndOpcode(currentPC, *currentPC);
154
155 OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)];
156
157 while (opGroup) {
158 if (opGroup->matches(m_opcode))
159 return opGroup->format(this);
160 opGroup = opGroup->next();
161 }
162
163 return A64DOpcode::format();
164}
165
166void A64DOpcode::bufferPrintf(const char* format, ...)
167{
168 if (m_bufferOffset >= bufferSize)
169 return;
170
171 va_list argList;
172 va_start(argList, format);
173
174 m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList);
175
176 va_end(argList);
177}
178
179const char* A64DOpcode::format()
180{
181 bufferPrintf(" .long %08x", m_opcode);
182 return m_formatBuffer;
183}
184
185void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit)
186{
187 if (registerNumber == 29) {
188 bufferPrintf(is64Bit ? "fp" : "wfp");
189 return;
190 }
191
192 if (registerNumber == 30) {
193 bufferPrintf(is64Bit ? "lr" : "wlr");
194 return;
195 }
196
197 bufferPrintf("%c%u", is64Bit ? 'x' : 'w', registerNumber);
198}
199
200void A64DOpcode::appendFPRegisterName(unsigned registerNumber, unsigned registerSize)
201{
202 bufferPrintf("%c%u", FPRegisterPrefix(registerSize), registerNumber);
203}
204
205const char* const A64DOpcodeAddSubtract::s_opNames[4] = { "add", "adds", "sub", "subs" };
206
207const char* A64DOpcodeAddSubtractImmediate::format()
208{
209 if (isCMP())
210 appendInstructionName(cmpName());
211 else {
212 if (isMovSP())
213 appendInstructionName("mov");
214 else
215 appendInstructionName(opName());
216 appendSPOrRegisterName(rd(), is64Bit());
217 appendSeparator();
218 }
219 appendSPOrRegisterName(rn(), is64Bit());
220
221 if (!isMovSP()) {
222 appendSeparator();
223 appendUnsignedImmediate(immed12());
224 if (shift()) {
225 appendSeparator();
226 appendString(shift() == 1 ? "lsl" : "reserved");
227 }
228 }
229 return m_formatBuffer;
230}
231
232const char* A64DOpcodeAddSubtractExtendedRegister::format()
233{
234 if (immediate3() > 4)
235 return A64DOpcode::format();
236
237 if (isCMP())
238 appendInstructionName(cmpName());
239 else {
240 appendInstructionName(opName());
241 appendSPOrRegisterName(rd(), is64Bit());
242 appendSeparator();
243 }
244 appendSPOrRegisterName(rn(), is64Bit());
245 appendSeparator();
246 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
247 appendSeparator();
248 if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
249 appendString("lsl");
250 else
251 appendString(optionName());
252 if (immediate3()) {
253 appendCharacter(' ');
254 appendUnsignedImmediate(immediate3());
255 }
256
257 return m_formatBuffer;
258}
259
260const char* A64DOpcodeAddSubtractShiftedRegister::format()
261{
262 if (!is64Bit() && immediate6() & 0x20)
263 return A64DOpcode::format();
264
265 if (shift() == 0x3)
266 return A64DOpcode::format();
267
268 if (isCMP())
269 appendInstructionName(cmpName());
270 else {
271 if (isNeg())
272 appendInstructionName(cmpName());
273 else
274 appendInstructionName(opName());
275 appendSPOrRegisterName(rd(), is64Bit());
276 appendSeparator();
277 }
278 if (!isNeg()) {
279 appendRegisterName(rn(), is64Bit());
280 appendSeparator();
281 }
282 appendZROrRegisterName(rm(), is64Bit());
283 if (immediate6()) {
284 appendSeparator();
285 appendShiftType(shift());
286 appendUnsignedImmediate(immediate6());
287 }
288
289 return m_formatBuffer;
290}
291
292const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" };
293const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = {
294 { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
295const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" };
296const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bfxil", "ubfx" };
297
298const char* A64DOpcodeBitfield::format()
299{
300 if (opc() == 0x3)
301 return A64DOpcode::format();
302
303 if (is64Bit() != nBit())
304 return A64DOpcode::format();
305
306 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
307 return A64DOpcode::format();
308
309 if (!(opc() & 0x1) && !immediateR()) {
310 // [un]signed {btye,half-word,word} extend
311 bool isSTXType = false;
312 if (immediateS() == 7) {
313 appendInstructionName(extendPseudoOpNames(0));
314 isSTXType = true;
315 } else if (immediateS() == 15) {
316 appendInstructionName(extendPseudoOpNames(1));
317 isSTXType = true;
318 } else if (immediateS() == 31 && is64Bit() && !opc()) {
319 appendInstructionName(extendPseudoOpNames(2));
320 isSTXType = true;
321 }
322
323 if (isSTXType) {
324 appendRegisterName(rd(), is64Bit());
325 appendSeparator();
326 appendRegisterName(rn(), false);
327
328 return m_formatBuffer;
329 }
330 }
331
332 if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
333 // asr/lsr
334 appendInstructionName(!opc() ? "asr" : "lsr");
335
336 appendRegisterName(rd(), is64Bit());
337 appendSeparator();
338 appendRegisterName(rn(), is64Bit());
339 appendSeparator();
340 appendUnsignedImmediate(immediateR());
341
342 return m_formatBuffer;
343 }
344
345 if (opc() == 0x2 && (immediateS() + 1) == immediateR()) {
346 // lsl
347 appendInstructionName("lsl");
348 appendRegisterName(rd(), is64Bit());
349 appendSeparator();
350 appendRegisterName(rn(), is64Bit());
351 appendSeparator();
352 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
353
354 return m_formatBuffer;
355 }
356
357 if (immediateS() < immediateR()) {
358 if (opc() != 1 || rn() != 0x1f) {
359 // bit field insert
360 appendInstructionName(insertOpNames());
361
362 appendRegisterName(rd(), is64Bit());
363 appendSeparator();
364 appendRegisterName(rn(), is64Bit());
365 appendSeparator();
366 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
367 appendSeparator();
368 appendUnsignedImmediate(immediateS() + 1);
369
370 return m_formatBuffer;
371 }
372
373 appendInstructionName(opName());
374 appendRegisterName(rd(), is64Bit());
375 appendSeparator();
376 appendRegisterName(rn(), is64Bit());
377 appendSeparator();
378 appendUnsignedImmediate(immediateR());
379 appendSeparator();
380 appendUnsignedImmediate(immediateS());
381
382 return m_formatBuffer;
383 }
384
385 // bit field extract
386 appendInstructionName(extractOpNames());
387
388 appendRegisterName(rd(), is64Bit());
389 appendSeparator();
390 appendRegisterName(rn(), is64Bit());
391 appendSeparator();
392 appendUnsignedImmediate(immediateR());
393 appendSeparator();
394 appendUnsignedImmediate(immediateS() - immediateR() + 1);
395
396 return m_formatBuffer;
397}
398
399const char* A64DOpcodeCompareAndBranchImmediate::format()
400{
401 appendInstructionName(opBit() ? "cbnz" : "cbz");
402 appendRegisterName(rt(), is64Bit());
403 appendSeparator();
404 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
405 return m_formatBuffer;
406}
407
408const char* A64DOpcodeConditionalBranchImmediate::format()
409{
410 bufferPrintf(" b.%-5.5s", conditionName(condition()));
411 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
412 return m_formatBuffer;
413}
414
415const char* const A64DOpcodeConditionalSelect::s_opNames[4] = {
416 "csel", "csinc", "csinv", "csneg"
417};
418
419const char* A64DOpcodeConditionalSelect::format()
420{
421 if (sBit())
422 return A64DOpcode::format();
423
424 if (op2() & 0x2)
425 return A64DOpcode::format();
426
427 if (rn() == rm() && (opNum() == 1 || opNum() == 2)) {
428 if (rn() == 31) {
429 appendInstructionName((opNum() == 1) ? "cset" : "csetm");
430 appendRegisterName(rd(), is64Bit());
431 } else {
432 appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
433 appendRegisterName(rd(), is64Bit());
434 appendSeparator();
435 appendZROrRegisterName(rn(), is64Bit());
436 }
437 appendSeparator();
438 appendString(conditionName(condition() ^ 0x1));
439
440 return m_formatBuffer;
441 }
442
443 appendInstructionName(opName());
444 appendRegisterName(rd(), is64Bit());
445 appendSeparator();
446 appendZROrRegisterName(rn(), is64Bit());
447 appendSeparator();
448 appendZROrRegisterName(rm(), is64Bit());
449 appendSeparator();
450 appendString(conditionName(condition()));
451
452 return m_formatBuffer;
453
454}
455
456const char* const A64DOpcodeDataProcessing1Source::s_opNames[8] = {
457 "rbit", "rev16", "rev32", "rev", "clz", "cls", 0, 0
458};
459
460const char* const A64DOpcodeDataProcessing1Source::s_pacAutOpNames[18] = {
461 "pacia", "pacib", "pacda", "pacdb", "autia", "autib", "autda", "autdb",
462 "paciza", "pacizb", "pacdza", "pacdzb", "autiza", "autizb", "autdza", "autdzb",
463 "xpaci", "xpacd"
464};
465
466const char* A64DOpcodeDataProcessing1Source::format()
467{
468 if (sBit())
469 return A64DOpcode::format();
470
471 if (opCode2() == 1 && is64Bit() && opCode() <= 0x1001) {
472 if (opCode() <= 0x00111 || rt() == 0x11111) {
473 appendInstructionName(s_pacAutOpNames[opCode()]);
474 appendZROrRegisterName(rd(), is64Bit());
475 if (opCode() <= 0x00111) {
476 appendSeparator();
477 appendZROrRegisterName(rn(), is64Bit());
478 }
479 return m_formatBuffer;
480 }
481 return A64DOpcode::format();
482 }
483
484 if (opCode2())
485 return A64DOpcode::format();
486
487 if (opCode() & 0x38)
488 return A64DOpcode::format();
489
490 if ((opCode() & 0x3e) == 0x6)
491 return A64DOpcode::format();
492
493 if (is64Bit() && opCode() == 0x3)
494 return A64DOpcode::format();
495
496 if (!is64Bit() && opCode() == 0x2)
497 appendInstructionName("rev");
498 else
499 appendInstructionName(opName());
500 appendZROrRegisterName(rd(), is64Bit());
501 appendSeparator();
502 appendZROrRegisterName(rn(), is64Bit());
503
504 return m_formatBuffer;
505}
506
507const char* const A64DOpcodeDataProcessing2Source::s_opNames[16] = {
508 // We use the pseudo-op names for the shift/rotate instructions
509 0, 0, "udiv", "sdiv", 0, 0, 0, 0,
510 "lsl", "lsr", "asr", "ror", 0, "pacga", 0, 0
511};
512
513const char* A64DOpcodeDataProcessing2Source::format()
514{
515 if (sBit())
516 return A64DOpcode::format();
517
518 if (!(opCode() & 0x3e))
519 return A64DOpcode::format();
520
521 if (opCode() & 0x30)
522 return A64DOpcode::format();
523
524 if ((opCode() & 0x3c) == 0x4)
525 return A64DOpcode::format();
526
527 const char* opcodeName = opName();
528 if (!opcodeName)
529 return A64DOpcode::format();
530
531 appendInstructionName(opcodeName);
532 appendZROrRegisterName(rd(), is64Bit());
533 appendSeparator();
534 appendZROrRegisterName(rn(), is64Bit());
535 appendSeparator();
536 appendZROrRegisterName(rm(), is64Bit());
537
538 return m_formatBuffer;
539}
540
541const char* const A64DOpcodeDataProcessing3Source::s_opNames[16] = {
542 "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0,
543 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0
544};
545
546const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames[16] = {
547 "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0,
548 0, 0, "umull", "umnegl", "umulh", 0, 0, 0
549};
550
551const char* A64DOpcodeDataProcessing3Source::format()
552{
553 if (op54())
554 return A64DOpcode::format();
555
556 if (opNum() > 12)
557 return A64DOpcode::format();
558
559 if (!is64Bit() && opNum() > 1)
560 return A64DOpcode::format();
561
562 if (!opName())
563 return A64DOpcode::format();
564
565 if ((opNum() & 0x4) && (ra() != 31))
566 return A64DOpcode::format();
567
568 appendInstructionName(opName());
569 appendZROrRegisterName(rd(), is64Bit());
570 appendSeparator();
571 bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2);
572 appendZROrRegisterName(rn(), srcOneAndTwoAre64Bit);
573 appendSeparator();
574 appendZROrRegisterName(rm(), srcOneAndTwoAre64Bit);
575
576 if (ra() != 31) {
577 appendSeparator();
578 appendRegisterName(ra(), is64Bit());
579 }
580
581 return m_formatBuffer;
582}
583
584const char* A64OpcodeExceptionGeneration::format()
585{
586 const char* opname = 0;
587 if (!op2()) {
588 switch (opc()) {
589 case 0x0: // SVC, HVC & SMC
590 switch (ll()) {
591 case 0x1:
592 opname = "svc";
593 break;
594 case 0x2:
595 opname = "hvc";
596 break;
597 case 0x3:
598 opname = "smc";
599 break;
600 }
601 break;
602 case 0x1: // BRK
603 if (!ll())
604 opname = "brk";
605 break;
606 case 0x2: // HLT
607 if (!ll())
608 opname = "hlt";
609 break;
610 case 0x5: // DPCS1-3
611 switch (ll()) {
612 case 0x1:
613 opname = "dpcs1";
614 break;
615 case 0x2:
616 opname = "dpcs2";
617 break;
618 case 0x3:
619 opname = "dpcs3";
620 break;
621 }
622 break;
623 }
624 }
625
626 if (!opname)
627 return A64DOpcode::format();
628
629 appendInstructionName(opname);
630 appendUnsignedImmediate(immediate16());
631 return m_formatBuffer;
632}
633
634const char* A64DOpcodeExtract::format()
635{
636 if (op21() || o0Bit())
637 return A64DOpcode::format();
638
639 if (is64Bit() != nBit())
640 return A64DOpcode::format();
641
642 if (!is64Bit() && (immediateS() & 0x20))
643 return A64DOpcode::format();
644
645 bool isROR = rn() == rm();
646 const char* opName = (isROR) ? "ror" : "extr";
647
648 appendInstructionName(opName);
649 appendZROrRegisterName(rd(), is64Bit());
650 appendSeparator();
651 appendZROrRegisterName(rn(), is64Bit());
652 if (!isROR) {
653 appendSeparator();
654 appendZROrRegisterName(rm(), is64Bit());
655 }
656 appendSeparator();
657 appendUnsignedImmediate(immediateS());
658
659 return m_formatBuffer;
660}
661
662const char* A64DOpcodeFloatingPointCompare::format()
663{
664 if (mBit())
665 return A64DOpcode::format();
666
667 if (sBit())
668 return A64DOpcode::format();
669
670 if (type() & 0x2)
671 return A64DOpcode::format();
672
673 if (op())
674 return A64DOpcode::format();
675
676 if (opCode2() & 0x7)
677 return A64DOpcode::format();
678
679 appendInstructionName(opName());
680 unsigned registerSize = type() + 2;
681 appendFPRegisterName(rn(), registerSize);
682 appendSeparator();
683 if (opCode2() & 0x8)
684 bufferPrintf("#0.0");
685 else
686 appendFPRegisterName(rm(), registerSize);
687
688 return m_formatBuffer;
689}
690
691const char* A64DOpcodeFloatingPointConditionalSelect::format()
692{
693 if (mBit())
694 return A64DOpcode::format();
695
696 if (sBit())
697 return A64DOpcode::format();
698
699 if (type() & 0x2)
700 return A64DOpcode::format();
701
702 appendInstructionName(opName());
703 unsigned registerSize = type() + 2;
704 appendFPRegisterName(rd(), registerSize);
705 appendSeparator();
706 appendFPRegisterName(rn(), registerSize);
707 appendSeparator();
708 appendFPRegisterName(rm(), registerSize);
709 appendSeparator();
710 appendString(conditionName(condition()));
711
712 return m_formatBuffer;
713}
714
715const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = {
716 "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
717 "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
718};
719
720const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
721{
722 if (mBit())
723 return A64DOpcode::format();
724
725 if (sBit())
726 return A64DOpcode::format();
727
728 if (opNum() > 16)
729 return A64DOpcode::format();
730
731 switch (type()) {
732 case 0:
733 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
734 return A64DOpcode::format();
735 break;
736 case 1:
737 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
738 return A64DOpcode::format();
739 break;
740 case 2:
741 return A64DOpcode::format();
742 case 3:
743 if ((opNum() < 0x4) || (opNum() > 0x5))
744 return A64DOpcode::format();
745 break;
746 }
747
748 appendInstructionName(opName());
749 if ((opNum() >= 0x4) && (opNum() <= 0x7)) {
750 unsigned srcRegisterSize = type() ^ 0x2; // 0:s, 1:d & 3:h
751 unsigned destRegisterSize = (opNum() & 0x3) ^ 0x2;
752 appendFPRegisterName(rd(), destRegisterSize);
753 appendSeparator();
754 appendFPRegisterName(rn(), srcRegisterSize);
755 } else {
756 unsigned registerSize = type() + 2;
757 appendFPRegisterName(rd(), registerSize);
758 appendSeparator();
759 appendFPRegisterName(rn(), registerSize);
760 }
761
762 return m_formatBuffer;
763}
764
765const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames[16] = {
766 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
767};
768
769const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
770{
771 if (mBit())
772 return A64DOpcode::format();
773
774 if (sBit())
775 return A64DOpcode::format();
776
777 if (type() & 0x2)
778 return A64DOpcode::format();
779
780 if (opNum() > 8)
781 return A64DOpcode::format();
782
783 appendInstructionName(opName());
784 unsigned registerSize = type() + 2;
785 appendFPRegisterName(rd(), registerSize);
786 appendSeparator();
787 appendFPRegisterName(rn(), registerSize);
788 appendSeparator();
789 appendFPRegisterName(rm(), registerSize);
790
791 return m_formatBuffer;
792}
793
794const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames[4] = {
795 "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
796};
797
798const char* A64DOpcodeFloatingFixedPointConversions::format()
799{
800 if (sBit())
801 return A64DOpcode::format();
802
803 if (type() & 0x2)
804 return A64DOpcode::format();
805
806 if (opcode() & 0x4)
807 return A64DOpcode::format();
808
809 if (!(rmode() & 0x1) && !(opcode() & 0x6))
810 return A64DOpcode::format();
811
812 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
813 return A64DOpcode::format();
814
815 if (!(rmode() & 0x2) && !(opcode() & 0x6))
816 return A64DOpcode::format();
817
818 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
819 return A64DOpcode::format();
820
821 if (!is64Bit() && scale() >= 32)
822 return A64DOpcode::format();
823
824 appendInstructionName(opName());
825 unsigned FPRegisterSize = type() + 2;
826 bool destIsFP = !rmode();
827
828 if (destIsFP) {
829 appendFPRegisterName(rd(), FPRegisterSize);
830 appendSeparator();
831 appendRegisterName(rn(), is64Bit());
832 } else {
833 appendRegisterName(rd(), is64Bit());
834 appendSeparator();
835 appendFPRegisterName(rn(), FPRegisterSize);
836 }
837 appendSeparator();
838 appendUnsignedImmediate(64 - scale());
839
840 return m_formatBuffer;
841}
842
843const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames[32] = {
844 "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov",
845 "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov",
846 "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0,
847 "fcvtzs", "fcvtzu", 0, 0, 0, 0, "fjcvtzs", 0
848};
849
850const char* A64DOpcodeFloatingPointIntegerConversions::format()
851{
852 if (sBit())
853 return A64DOpcode::format();
854
855 if (type() == 0x3)
856 return A64DOpcode::format();
857
858 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4)))
859 return A64DOpcode::format();
860
861 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
862 return A64DOpcode::format();
863
864 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
865 return A64DOpcode::format();
866
867 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
868 return A64DOpcode::format();
869
870 if (!opName())
871 return A64DOpcode::format();
872
873 if ((opNum() & 0x1e) == 0xe) {
874 // Handle fmov to/from upper half of quad separately
875 if (!is64Bit() || (type() != 0x2))
876 return A64DOpcode::format();
877
878 appendInstructionName(opName());
879 if (opcode() & 0x1) {
880 // fmov Vd.D[1], Xn
881 bufferPrintf("V%u.D[1]", rd());
882 appendSeparator();
883 appendZROrRegisterName(rn());
884 } else {
885 // fmov Xd, Vn.D[1]
886 appendZROrRegisterName(rd());
887 appendSeparator();
888 bufferPrintf("V%u.D[1]", rn());
889 }
890
891 return m_formatBuffer;
892 }
893
894 appendInstructionName(opName());
895 unsigned FPRegisterSize = type() + 2;
896 bool destIsFP = ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
897
898 if (destIsFP) {
899 appendFPRegisterName(rd(), FPRegisterSize);
900 appendSeparator();
901 appendZROrRegisterName(rn(), is64Bit());
902 } else {
903 appendZROrRegisterName(rd(), is64Bit());
904 appendSeparator();
905 appendFPRegisterName(rn(), FPRegisterSize);
906 }
907
908 return m_formatBuffer;
909}
910
911const char* A64DOpcodeMSRImmediate::format()
912{
913 const char* pstateField = nullptr;
914
915 if (!op1() && (op2() == 0x5))
916 pstateField = "spsel";
917
918 if ((op1() == 0x3) && (op2() == 0x6))
919 pstateField = "daifset";
920
921 if ((op1() == 0x3) && (op2() == 0x7))
922 pstateField = "daifclr";
923
924 if (!!op1() && !(op2() & 0x4))
925 return A64DOpcode::format();
926
927 if (!pstateField)
928 return A64DOpcode::format();
929
930 appendInstructionName("msr");
931 appendString(pstateField);
932 appendSeparator();
933 appendUnsignedImmediate(crM());
934
935 return m_formatBuffer;
936}
937
938const char* A64DOpcodeMSROrMRSRegister::format()
939{
940 appendInstructionName(opName());
941
942 if (lBit()) {
943 appendZROrRegisterName(rt());
944 appendSeparator();
945 }
946
947 bufferPrintf("S%u_%u_C%u_C%u_%u", op0(), op1(), crN(), crM(), op2());
948
949 if (!lBit()) {
950 appendSeparator();
951 appendZROrRegisterName(rt());
952 }
953
954 const char* systemRegisterName = nullptr;
955
956 switch (systemRegister()) {
957 case 0b1101100000000001:
958 systemRegisterName = "ctr_el0";
959 break;
960 case 0b1101101000010000:
961 systemRegisterName = "nzcv";
962 break;
963 case 0b1101101000010001:
964 systemRegisterName = "daif";
965 break;
966 case 0b1101101000100000:
967 systemRegisterName = "fpcr";
968 break;
969 case 0b1101101000100001:
970 systemRegisterName = "fpsr";
971 break;
972 case 0b1101111010000010:
973 systemRegisterName = "tpidr_el0";
974 break;
975 case 0b1101111010000011:
976 systemRegisterName = "tpidrr0_el0";
977 break;
978 }
979
980 if (systemRegisterName) {
981 appendString(" ; ");
982 appendString(systemRegisterName);
983 }
984 return m_formatBuffer;
985}
986
987const char* const A64DOpcodeHint::s_opNames[32] = {
988 "nop", "yield", "wfe", "wfi", "sev", "sevl", 0, "xpaclri",
989 "pacia1716", 0, "pacib1716", 0, "autia1716", 0, "autib1716", 0,
990 0, 0, 0, 0, 0, 0, 0, 0,
991 "paciaz", "paciasp", "pacibz", "pacibsp", "autiaz", "autiasp", "autibz", "autibsp"
992};
993
994const char* A64DOpcodeHint::format()
995{
996 appendInstructionName(opName());
997
998 if (immediate7() >= 32 || !s_opNames[immediate7()])
999 appendUnsignedImmediate(immediate7());
1000
1001 return m_formatBuffer;
1002}
1003
1004const char* A64DOpcodeHint::opName()
1005{
1006 const char* opName = (immediate7() < 32 ? s_opNames[immediate7()] : 0);
1007 if (!opName)
1008 return "hint";
1009
1010 return opName;
1011}
1012
1013const char* const A64DOpcodeSystemSync::s_opNames[8] = {
1014 0, 0, "clrex", 0, "dsb", "dmb", "isb", 0
1015};
1016
1017const char* const A64DOpcodeSystemSync::s_optionNames[16] = {
1018 0, "oshld", "oshst", "osh", 0, "nshld", "nshst", "nsh",
1019 0, "ishld", "ishst", "ish", 0, "ld", "st", "sy"
1020};
1021
1022const char* A64DOpcodeSystemSync::format()
1023{
1024 const char* thisOpName = opName();
1025
1026 if (!thisOpName)
1027 return A64DOpcode::format();
1028
1029 appendInstructionName(thisOpName);
1030
1031 if (op2() & 0x2) {
1032 if (crM() != 0xf) {
1033 appendCharacter('#');
1034 appendUnsignedImmediate(crM());
1035 }
1036 } else {
1037 const char* thisOption = option();
1038 if (thisOption)
1039 appendString(thisOption);
1040 else
1041 appendUnsignedImmediate(crM());
1042 }
1043
1044 return m_formatBuffer;
1045}
1046
1047const char* const A64DOpcodeLoadStoreExclusive::s_opNames[64] = {
1048 "stxrb", "stlxrb", 0, 0, "ldxrb", "ldaxrb", 0, 0,
1049 0, "stlrb", 0, 0, 0, "ldarb", 0, 0,
1050 "stxrh", "stlxrh", 0, 0, "ldxrh", "ldaxrh", 0, 0,
1051 0, "stlrh", 0, 0, 0, "ldarh", 0, 0,
1052 "stxr", "stlxr", "stxp", "stlxp", "ldxr", "ldaxr", "ldxp", "ldaxp",
1053 0, "stlr", 0, 0, 0, "ldar", 0, 0,
1054 "stxr", "stlxr", "stxp", "stlxp", "ldxr", "ldaxr", "ldxp", "ldaxp",
1055 0, "stlr", 0, 0, 0, "ldar", 0, 0
1056};
1057
1058const char* A64DOpcodeLoadStoreExclusive::format()
1059{
1060 if (o2() && !o1() && !o0())
1061 return A64DOpcode::format();
1062
1063 if (o2() && o1())
1064 return A64DOpcode::format();
1065
1066 if ((size() < 2) && o1())
1067 return A64DOpcode::format();
1068
1069 if (loadBit() && (rs() != 0x1f))
1070 return A64DOpcode::format();
1071
1072 if (!isPairOp() && (rt2() != 0x1f))
1073 return A64DOpcode::format();
1074
1075 const char* thisOpName = opName();
1076
1077 if (!thisOpName)
1078 return A64DOpcode::format();
1079
1080 appendInstructionName(thisOpName);
1081
1082 if (!loadBit()) {
1083 appendZROrRegisterName(rs(), size() == 0x3);
1084 appendSeparator();
1085 }
1086
1087 appendZROrRegisterName(rt(), size() == 0x3);
1088 appendSeparator();
1089 if (isPairOp()) {
1090 appendZROrRegisterName(rt2(), size() == 0x3);
1091 appendSeparator();
1092 }
1093 appendCharacter('[');
1094 appendSPOrRegisterName(rn());
1095 appendCharacter(']');
1096
1097 return m_formatBuffer;
1098}
1099
1100// A zero in an entry of the table means the instruction is Unallocated
1101const char* const A64DOpcodeLoadStore::s_opNames[32] = {
1102 "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
1103 "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0,
1104 "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0,
1105 "str", "ldr", 0, 0, "str", "ldr", 0, 0
1106};
1107
1108// A zero in an entry of the table means the instruction is Unallocated
1109const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames[32] = {
1110 "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0,
1111 "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0,
1112 "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0,
1113 "sttr", "ldtr", 0, 0, 0, 0, 0, 0
1114};
1115
1116// A zero in an entry of the table means the instruction is Unallocated
1117const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames[32] = {
1118 "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur",
1119 "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0,
1120 "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0,
1121 "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0
1122};
1123
1124const char* A64DOpcodeLoadStoreImmediate::format()
1125{
1126 const char* thisOpName;
1127
1128 if (type() & 0x1)
1129 thisOpName = opName();
1130 else if (!type())
1131 thisOpName = unscaledOpName();
1132 else
1133 thisOpName = unprivilegedOpName();
1134
1135 if (!thisOpName)
1136 return A64DOpcode::format();
1137
1138 appendInstructionName(thisOpName);
1139 if (vBit())
1140 appendFPRegisterName(rt(), size());
1141 else if (!opc())
1142 appendZROrRegisterName(rt(), is64BitRT());
1143 else
1144 appendRegisterName(rt(), is64BitRT());
1145 appendSeparator();
1146 appendCharacter('[');
1147 appendSPOrRegisterName(rn());
1148
1149 switch (type()) {
1150 case 0: // Unscaled Immediate
1151 if (immediate9()) {
1152 appendSeparator();
1153 appendSignedImmediate(immediate9());
1154 }
1155 appendCharacter(']');
1156 break;
1157 case 1: // Immediate Post-Indexed
1158 appendCharacter(']');
1159 if (immediate9()) {
1160 appendSeparator();
1161 appendSignedImmediate(immediate9());
1162 }
1163 break;
1164 case 2: // Unprivileged
1165 if (immediate9()) {
1166 appendSeparator();
1167 appendSignedImmediate(immediate9());
1168 }
1169 appendCharacter(']');
1170 break;
1171 case 3: // Immediate Pre-Indexed
1172 if (immediate9()) {
1173 appendSeparator();
1174 appendSignedImmediate(immediate9());
1175 }
1176 appendCharacter(']');
1177 appendCharacter('!');
1178 break;
1179 }
1180
1181 return m_formatBuffer;
1182}
1183
1184const char* A64DOpcodeLoadStoreRegisterOffset::format()
1185{
1186 const char* thisOpName = opName();
1187
1188 if (!thisOpName)
1189 return A64DOpcode::format();
1190
1191 if (!(option() & 0x2))
1192 return A64DOpcode::format();
1193
1194 appendInstructionName(thisOpName);
1195 unsigned scale;
1196 if (vBit()) {
1197 appendFPRegisterName(rt(), size());
1198 scale = ((opc() & 2)<<1) | size();
1199 } else {
1200 if (!opc())
1201 appendZROrRegisterName(rt(), is64BitRT());
1202 else
1203 appendRegisterName(rt(), is64BitRT());
1204 scale = size();
1205 }
1206 appendSeparator();
1207 appendCharacter('[');
1208 appendSPOrRegisterName(rn());
1209 if (rm() != 31) {
1210 appendSeparator();
1211 appendRegisterName(rm(), (option() & 0x3) == 0x3);
1212
1213 unsigned shift = sBit() ? scale : 0;
1214
1215 if (option() == 0x3) {
1216 if (shift) {
1217 appendSeparator();
1218 appendString("lsl ");
1219 appendUnsignedImmediate(shift);
1220 }
1221 } else {
1222 appendSeparator();
1223 appendString(optionName());
1224 if (shift)
1225 appendUnsignedImmediate(shift);
1226 }
1227 }
1228
1229 appendCharacter(']');
1230
1231 return m_formatBuffer;
1232}
1233
1234const char* const A64DOpcodeLoadStoreAuthenticated::s_opNames[2] = {
1235 "ldraa", "ldrab"
1236};
1237
1238const char* A64DOpcodeLoadStoreAuthenticated::format()
1239{
1240 appendInstructionName(opName());
1241 appendRegisterName(rt());
1242 appendSeparator();
1243 appendCharacter('[');
1244 appendSPOrRegisterName(rn());
1245
1246 if (wBit() || immediate10()) {
1247 appendSeparator();
1248 appendSignedImmediate(immediate10() << size());
1249 }
1250 appendCharacter(']');
1251
1252 if (wBit())
1253 appendCharacter('!');
1254
1255 return m_formatBuffer;
1256}
1257
1258const char* A64DOpcodeLoadStoreRegisterPair::opName()
1259{
1260 if (!vBit() && lBit() && size() == 0x1)
1261 return "ldpsw";
1262 if (lBit())
1263 return "ldp";
1264 return "stp";
1265}
1266
1267const char* A64DOpcodeLoadStoreRegisterPair::format()
1268{
1269 const char* thisOpName = opName();
1270
1271 if (size() == 0x3)
1272 return A64DOpcode::format();
1273
1274 if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
1275 return A64DOpcode::format();
1276
1277 if ((offsetMode() == 0x1) && !vBit() && !lBit())
1278 return A64DOpcode::format();
1279
1280 appendInstructionName(thisOpName);
1281 unsigned offsetShift;
1282 if (vBit()) {
1283 appendFPRegisterName(rt(), size());
1284 appendSeparator();
1285 appendFPRegisterName(rt2(), size());
1286 offsetShift = size() + 2;
1287 } else {
1288 if (!lBit())
1289 appendZROrRegisterName(rt(), is64Bit());
1290 else
1291 appendRegisterName(rt(), is64Bit());
1292 appendSeparator();
1293 if (!lBit())
1294 appendZROrRegisterName(rt2(), is64Bit());
1295 else
1296 appendRegisterName(rt2(), is64Bit());
1297 offsetShift = (size() >> 1) + 2;
1298 }
1299
1300 appendSeparator();
1301 appendCharacter('[');
1302 appendSPOrRegisterName(rn());
1303
1304 int offset = immediate7() << offsetShift;
1305
1306 if (offsetMode() == 1) {
1307 appendCharacter(']');
1308 appendSeparator();
1309 appendSignedImmediate(offset);
1310 } else {
1311 appendSeparator();
1312 appendSignedImmediate(offset);
1313 appendCharacter(']');
1314 if (offsetMode() == 0x3)
1315 appendCharacter('!');
1316 }
1317
1318 return m_formatBuffer;
1319}
1320
1321const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
1322{
1323 const char* thisOpName = opName();
1324
1325 if (!thisOpName)
1326 return A64DOpcode::format();
1327
1328 appendInstructionName(thisOpName);
1329 unsigned scale;
1330 if (vBit()) {
1331 appendFPRegisterName(rt(), size());
1332 scale = ((opc() & 2)<<1) | size();
1333 } else {
1334 if (!opc())
1335 appendZROrRegisterName(rt(), is64BitRT());
1336 else
1337 appendRegisterName(rt(), is64BitRT());
1338 scale = size();
1339 }
1340 appendSeparator();
1341 appendCharacter('[');
1342 appendSPOrRegisterName(rn());
1343
1344 if (immediate12()) {
1345 appendSeparator();
1346 appendUnsignedImmediate(immediate12() << scale);
1347 }
1348
1349 appendCharacter(']');
1350
1351 return m_formatBuffer;
1352}
1353
1354// A zero in an entry of the table means the instruction is Unallocated
1355const char* const A64DOpcodeLogical::s_opNames[8] = {
1356 "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics"
1357};
1358
1359const char* A64DOpcodeLogicalShiftedRegister::format()
1360{
1361 if (!is64Bit() && immediate6() & 0x20)
1362 return A64DOpcode::format();
1363
1364 if (isTst())
1365 appendInstructionName("tst");
1366 else {
1367 if (isMov())
1368 appendInstructionName(nBit() ? "mvn" : "mov");
1369 else
1370 appendInstructionName(opName(opNumber()));
1371 appendZROrRegisterName(rd(), is64Bit());
1372 appendSeparator();
1373 }
1374
1375 if (!isMov()) {
1376 appendZROrRegisterName(rn(), is64Bit());
1377 appendSeparator();
1378 }
1379
1380 appendZROrRegisterName(rm(), is64Bit());
1381 if (immediate6()) {
1382 appendSeparator();
1383 appendShiftType(shift());
1384 appendUnsignedImmediate(immediate6());
1385 }
1386
1387 return m_formatBuffer;
1388}
1389
1390static unsigned highestBitSet(unsigned value)
1391{
1392 unsigned result = 0;
1393
1394 while (value >>= 1)
1395 result++;
1396
1397 return result;
1398}
1399
1400static uint64_t rotateRight(uint64_t value, unsigned width, unsigned shift)
1401{
1402 uint64_t result = value;
1403
1404 if (shift)
1405 result = (value >> (shift % width)) | (value << (width - shift));
1406
1407 return result;
1408}
1409
1410static uint64_t replicate(uint64_t value, unsigned width)
1411{
1412 uint64_t result = 0;
1413
1414 for (unsigned totalBits = 0; totalBits < 64; totalBits += width)
1415 result = (result << width) | value;
1416
1417 return result;
1418}
1419
1420const char* A64DOpcodeLogicalImmediate::format()
1421{
1422 if (!is64Bit() && nBit())
1423 return A64DOpcode::format();
1424
1425 unsigned len = highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
1426 unsigned levels = (1 << len) - 1; // len number of 1 bits starting at LSB
1427
1428 if ((immediateS() & levels) == levels)
1429 return A64DOpcode::format();
1430
1431 unsigned r = immediateR() & levels;
1432 unsigned s = immediateS() & levels;
1433 unsigned eSize = 1 << len;
1434 uint64_t pattern = rotateRight((1ull << (s + 1)) - 1, eSize, r);
1435
1436 uint64_t immediate = replicate(pattern, eSize);
1437
1438 if (!is64Bit())
1439 immediate &= 0xffffffffull;
1440
1441 if (isTst())
1442 appendInstructionName("tst");
1443 else {
1444 if (isMov())
1445 appendInstructionName("mov");
1446 else
1447 appendInstructionName(opName(opNumber()));
1448 appendRegisterName(rd(), is64Bit());
1449 appendSeparator();
1450 }
1451 if (!isMov()) {
1452 appendRegisterName(rn(), is64Bit());
1453 appendSeparator();
1454 }
1455 appendUnsignedImmediate64(immediate);
1456
1457 return m_formatBuffer;
1458}
1459
1460const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", 0, "movz", "movk" };
1461
1462const char* A64DOpcodeMoveWide::format()
1463{
1464 if (opc() == 1)
1465 return A64DOpcode::format();
1466 if (!is64Bit() && hw() >= 2)
1467 return A64DOpcode::format();
1468
1469 if (!opc() && (!immediate16() || !hw()) && (is64Bit() || immediate16() != 0xffff)) {
1470 // MOV pseudo op for MOVN
1471 appendInstructionName("mov");
1472 appendRegisterName(rd(), is64Bit());
1473 appendSeparator();
1474
1475 if (is64Bit()) {
1476 int64_t amount = immediate16() << (hw() * 16);
1477 amount = ~amount;
1478 appendSignedImmediate64(amount);
1479 } else {
1480 int32_t amount = immediate16() << (hw() * 16);
1481 amount = ~amount;
1482 appendSignedImmediate(amount);
1483 }
1484 } else {
1485 appendInstructionName(opName());
1486 appendRegisterName(rd(), is64Bit());
1487 appendSeparator();
1488 appendUnsignedHexImmediate(immediate16());
1489 if (hw()) {
1490 appendSeparator();
1491 appendShiftAmount(hw());
1492 }
1493 }
1494
1495 return m_formatBuffer;
1496}
1497
1498const char* A64DOpcodeTestAndBranchImmediate::format()
1499{
1500 appendInstructionName(opBit() ? "tbnz" : "tbz");
1501 appendRegisterName(rt());
1502 appendSeparator();
1503 appendUnsignedImmediate(bitNumber());
1504 appendSeparator();
1505 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate14()));
1506 return m_formatBuffer;
1507}
1508
1509const char* A64DOpcodeUnconditionalBranchImmediate::format()
1510{
1511 appendInstructionName(op() ? "bl" : "b");
1512 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate26()));
1513 return m_formatBuffer;
1514}
1515
1516const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
1517const char* const A64DOpcodeUnconditionalBranchRegister::s_AuthOpNames[20] = {
1518 "braaz", "brabz", "blraaz", "blrabz", "retaa", "retab", 0, 0,
1519 "eretaa", "eretab", 0, 0, 0, 0, 0, 0,
1520 "braa", "brab", "blraa", "blrab"
1521};
1522
1523const char* A64DOpcodeUnconditionalBranchRegister::authOpName()
1524{
1525 unsigned opCode = authOpCode();
1526 if (opCode >= 20)
1527 return 0;
1528 return s_AuthOpNames[opCode];
1529}
1530
1531const char* A64DOpcodeUnconditionalBranchRegister::format()
1532{
1533 unsigned opcValue = opc();
1534 if (op2() == 0x1f && (op3() & 0x3e) == 0x2) {
1535 const char* opName = authOpName();
1536 if (!opName)
1537 return A64DOpcode::format();
1538 if (rn() != 0x1f && (opcValue == 0x2 || opcValue == 0x4))
1539 return A64DOpcode::format();
1540
1541 appendInstructionName(opName);
1542 if ((opcValue & 0x7) <= 0x1)
1543 appendRegisterName(rn());
1544 if (opcValue & 0x8) {
1545 appendSeparator();
1546 appendRegisterName(rm());
1547 }
1548
1549 return m_formatBuffer;
1550 }
1551 if (opcValue == 3 || opcValue > 5)
1552 return A64DOpcode::format();
1553 if (((opcValue & 0xe) == 0x4) && rn() != 0x1f)
1554 return A64DOpcode::format();
1555 appendInstructionName(opName());
1556 if (opcValue <= 2)
1557 appendRegisterName(rn());
1558 return m_formatBuffer;
1559}
1560
1561} } // namespace JSC::ARM64Disassembler
1562
1563#endif // USE(ARM64_DISASSEMBLER)
1564