2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "A64DOpcode.h"
33 namespace JSC
{ namespace ARM64Disassembler
{
35 A64DOpcode::OpcodeGroup
* A64DOpcode::opcodeTable
[32];
37 const char* const A64DOpcode::s_conditionNames
[16] = {
38 "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
39 "hi", "ls", "ge", "lt", "gt", "le", "al", "ne"
42 const char* const A64DOpcode::s_optionName
[8] =
43 { "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx" };
45 const char* const A64DOpcode::s_shiftNames
[4] = {
46 "lsl", "lsr", "asl", "ror"
49 const char A64DOpcode::s_FPRegisterPrefix
[5] = {
50 'b', 'h', 's', 'd', 'q'
53 struct OpcodeGroupInitializer
{
54 unsigned m_opcodeGroupNumber
;
57 const char* (*m_format
)(A64DOpcode
*);
60 #define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
61 { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
63 static OpcodeGroupInitializer opcodeGroupList
[] = {
64 OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister
),
65 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister
),
66 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister
),
67 OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate
),
68 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide
),
69 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate
),
70 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield
),
71 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract
),
72 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate
),
73 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate
),
74 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate
),
75 OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration
),
76 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate
),
77 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate
),
78 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate
),
79 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint
),
80 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate
),
81 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister
),
82 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate
),
83 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate
),
84 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister
),
85 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate
),
86 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate
),
87 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset
),
88 OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate
),
89 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect
),
90 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source
),
91 OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source
),
92 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate
),
93 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset
),
94 OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate
),
95 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare
),
96 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source
),
97 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source
),
98 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions
),
99 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions
),
102 bool A64DOpcode::s_initialized
= false;
104 void A64DOpcode::init()
109 OpcodeGroup
* lastGroups
[32];
111 for (unsigned i
= 0; i
< 32; i
++) {
116 for (unsigned i
= 0; i
< sizeof(opcodeGroupList
) / sizeof(struct OpcodeGroupInitializer
); i
++) {
117 OpcodeGroup
* newOpcodeGroup
= new OpcodeGroup(opcodeGroupList
[i
].m_mask
, opcodeGroupList
[i
].m_pattern
, opcodeGroupList
[i
].m_format
);
118 uint32_t opcodeGroupNumber
= opcodeGroupList
[i
].m_opcodeGroupNumber
;
120 if (!opcodeTable
[opcodeGroupNumber
])
121 opcodeTable
[opcodeGroupNumber
] = newOpcodeGroup
;
123 lastGroups
[opcodeGroupNumber
]->setNext(newOpcodeGroup
);
124 lastGroups
[opcodeGroupNumber
] = newOpcodeGroup
;
127 s_initialized
= true;
130 void A64DOpcode::setPCAndOpcode(uint32_t* newPC
, uint32_t newOpcode
)
133 m_opcode
= newOpcode
;
135 m_formatBuffer
[0] = '\0';
138 const char* A64DOpcode::disassemble(uint32_t* currentPC
)
140 setPCAndOpcode(currentPC
, *currentPC
);
142 OpcodeGroup
* opGroup
= opcodeTable
[opcodeGroupNumber(m_opcode
)];
145 if (opGroup
->matches(m_opcode
))
146 return opGroup
->format(this);
147 opGroup
= opGroup
->next();
150 return A64DOpcode::format();
153 void A64DOpcode::bufferPrintf(const char* format
, ...)
155 if (m_bufferOffset
>= bufferSize
)
159 va_start(argList
, format
);
161 m_bufferOffset
+= vsnprintf(m_formatBuffer
+ m_bufferOffset
, bufferSize
- m_bufferOffset
, format
, argList
);
166 const char* A64DOpcode::format()
168 bufferPrintf(" .long %08x", m_opcode
);
169 return m_formatBuffer
;
172 void A64DOpcode::appendRegisterName(unsigned registerNumber
, bool is64Bit
)
174 if (registerNumber
== 30) {
175 bufferPrintf(is64Bit
? "lr" : "wlr");
179 bufferPrintf("%c%u", is64Bit
? 'x' : 'w', registerNumber
);
182 void A64DOpcode::appendFPRegisterName(unsigned registerNumber
, unsigned registerSize
)
184 bufferPrintf("%c%u", FPRegisterPrefix(registerSize
), registerNumber
);
187 const char* const A64DOpcodeAddSubtract::s_opNames
[4] = { "add", "adds", "sub", "subs" };
189 const char* A64DOpcodeAddSubtractImmediate::format()
192 appendInstructionName(cmpName());
195 appendInstructionName("mov");
197 appendInstructionName(opName());
198 appendSPOrRegisterName(rd(), is64Bit());
201 appendSPOrRegisterName(rn(), is64Bit());
205 appendUnsignedImmediate(immed12());
208 appendString(shift() == 1 ? "lsl" : "reserved");
211 return m_formatBuffer
;
214 const char* A64DOpcodeAddSubtractExtendedRegister::format()
216 if (immediate3() > 4)
217 return A64DOpcode::format();
220 appendInstructionName(cmpName());
222 appendInstructionName(opName());
223 appendSPOrRegisterName(rd(), is64Bit());
226 appendSPOrRegisterName(rn(), is64Bit());
228 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
230 if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
233 appendString(optionName());
235 appendCharacter(' ');
236 appendUnsignedImmediate(immediate3());
239 return m_formatBuffer
;
242 const char* A64DOpcodeAddSubtractShiftedRegister::format()
244 if (!is64Bit() && immediate6() & 0x20)
245 return A64DOpcode::format();
248 return A64DOpcode::format();
251 appendInstructionName(cmpName());
254 appendInstructionName(cmpName());
256 appendInstructionName(opName());
257 appendSPOrRegisterName(rd(), is64Bit());
261 appendRegisterName(rn(), is64Bit());
264 appendZROrRegisterName(rm(), is64Bit());
267 appendShiftType(shift());
268 appendUnsignedImmediate(immediate6());
271 return m_formatBuffer
;
274 const char* const A64DOpcodeBitfield::s_opNames
[3] = { "sbfm", "bfm", "ubfm" };
275 const char* const A64DOpcodeBitfield::s_extendPseudoOpNames
[3][3] = {
276 { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
277 const char* const A64DOpcodeBitfield::s_insertOpNames
[3] = { "sbfiz", "bfi", "ubfiz" };
278 const char* const A64DOpcodeBitfield::s_extractOpNames
[3] = { "sbfx", "bf", "ubfx" };
280 const char* A64DOpcodeBitfield::format()
283 return A64DOpcode::format();
285 if (is64Bit() != nBit())
286 return A64DOpcode::format();
288 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
289 return A64DOpcode::format();
291 if (!(opc() & 0x1) && !immediateR()) {
292 // [un]signed {btye,half-word,word} extend
293 bool isSTXType
= false;
294 if (immediateS() == 7) {
295 appendInstructionName(extendPseudoOpNames(0));
297 } else if (immediateS() == 15) {
298 appendInstructionName(extendPseudoOpNames(1));
300 } else if (immediateS() == 31 && is64Bit()) {
301 appendInstructionName(extendPseudoOpNames(2));
306 appendRegisterName(rd(), is64Bit());
308 appendRegisterName(rn(), false);
310 return m_formatBuffer
;
314 if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
316 appendInstructionName("lsl");
317 appendRegisterName(rd(), is64Bit());
319 appendRegisterName(rn(), is64Bit());
321 appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
323 return m_formatBuffer
;
324 } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
326 appendInstructionName(!opc() ? "ars" : "lsr");
328 appendRegisterName(rd(), is64Bit());
330 appendRegisterName(rn(), is64Bit());
332 appendUnsignedImmediate(immediateR());
334 return m_formatBuffer
;
335 } else if (immediateS() < immediateR()) {
337 appendInstructionName(insertOpNames());
339 appendRegisterName(rd(), is64Bit());
341 appendRegisterName(rn(), is64Bit());
343 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
345 appendUnsignedImmediate(immediateS() + 1);
347 return m_formatBuffer
;
350 appendInstructionName(extractOpNames());
352 appendRegisterName(rd(), is64Bit());
354 appendRegisterName(rn(), is64Bit());
356 appendUnsignedImmediate(immediateR());
358 appendUnsignedImmediate(immediateS() - immediateR() + 1);
360 return m_formatBuffer
;
363 appendInstructionName(opName());
364 appendRegisterName(rd(), is64Bit());
366 appendRegisterName(rn(), is64Bit());
368 appendUnsignedImmediate(immediateR());
370 appendUnsignedImmediate(immediateS());
372 return m_formatBuffer
;
375 const char* A64DOpcodeCompareAndBranchImmediate::format()
377 appendInstructionName(opBit() ? "cbnz" : "cbz");
378 appendRegisterName(rt(), is64Bit());
380 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate19()));
381 return m_formatBuffer
;
384 const char* A64DOpcodeConditionalBranchImmediate::format()
386 bufferPrintf(" b.%-5.5s", conditionName(condition()));
387 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate19()));
388 return m_formatBuffer
;
391 const char* const A64DOpcodeConditionalSelect::s_opNames
[4] = {
392 "csel", "csinc", "csinv", "csneg"
395 const char* A64DOpcodeConditionalSelect::format()
398 return A64DOpcode::format();
401 return A64DOpcode::format();
403 if (rn() == rm() && (opNum() == 1 || opNum() == 2))
406 appendInstructionName((opNum() == 1) ? "cset" : "csetm");
407 appendRegisterName(rd(), is64Bit());
409 appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
410 appendRegisterName(rd(), is64Bit());
412 appendZROrRegisterName(rn(), is64Bit());
415 appendString(conditionName(condition() ^ 0x1));
417 return m_formatBuffer
;
420 appendInstructionName(opName());
421 appendRegisterName(rd(), is64Bit());
423 appendZROrRegisterName(rn(), is64Bit());
425 appendZROrRegisterName(rm(), is64Bit());
427 appendString(conditionName(condition()));
429 return m_formatBuffer
;
433 const char* const A64DOpcodeDataProcessing2Source::s_opNames
[8] = {
434 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions
437 const char* A64DOpcodeDataProcessing2Source::format()
440 return A64DOpcode::format();
442 if (!(opCode() & 0x3e))
443 return A64DOpcode::format();
446 return A64DOpcode::format();
448 if ((opCode() & 0x34) == 0x4)
449 return A64DOpcode::format();
451 appendInstructionName(opName());
452 appendRegisterName(rd(), is64Bit());
454 appendRegisterName(rn(), is64Bit());
456 appendRegisterName(rm(), is64Bit());
458 return m_formatBuffer
;
461 const char* const A64DOpcodeDataProcessing3Source::s_opNames
[16] = {
462 "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0,
463 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0
466 const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames
[16] = {
467 "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0,
468 0, 0, "umull", "umnegl", "umulh", 0, 0, 0
471 const char* A64DOpcodeDataProcessing3Source::format()
474 return A64DOpcode::format();
477 return A64DOpcode::format();
479 if (!is64Bit() && opNum() > 1)
480 return A64DOpcode::format();
483 return A64DOpcode::format();
485 appendInstructionName(opName());
486 appendRegisterName(rd(), is64Bit());
488 bool srcOneAndTwoAre64Bit
= is64Bit() & !(opNum() & 0x2);
489 appendRegisterName(rn(), srcOneAndTwoAre64Bit
);
491 appendRegisterName(rm(), srcOneAndTwoAre64Bit
);
493 if ((ra() != 31) || !(opNum() & 0x4)) {
495 appendRegisterName(ra(), is64Bit());
498 return m_formatBuffer
;
501 const char* A64OpcodeExceptionGeneration::format()
503 const char* opname
= 0;
506 case 0x0: // SVC, HVC & SMC
544 return A64DOpcode::format();
546 appendInstructionName(opname
);
547 appendUnsignedImmediate(immediate16());
548 return m_formatBuffer
;
551 const char* A64DOpcodeExtract::format()
553 if (!op21() || !o0Bit())
554 return A64DOpcode::format();
556 if (is64Bit() != nBit())
557 return A64DOpcode::format();
559 if (is64Bit() && (immediateS() & 0x20))
560 return A64DOpcode::format();
562 const char* opName
= (rn() == rm()) ? "ror" : "extr";
564 appendInstructionName(opName
);
565 appendRegisterName(rd(), is64Bit());
567 appendRegisterName(rn(), is64Bit());
569 appendRegisterName(rm(), is64Bit());
571 appendUnsignedImmediate(immediateS());
573 return m_formatBuffer
;
576 const char* A64DOpcodeFloatingPointCompare::format()
579 return A64DOpcode::format();
582 return A64DOpcode::format();
585 return A64DOpcode::format();
588 return A64DOpcode::format();
591 return A64DOpcode::format();
593 appendInstructionName(opName());
594 unsigned registerSize
= type() + 2;
595 appendFPRegisterName(rn(), registerSize
);
598 bufferPrintf("#0.0");
600 appendFPRegisterName(rm(), registerSize
);
602 return m_formatBuffer
;
605 const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames
[16] = {
606 "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
607 "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
610 const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
613 return A64DOpcode::format();
616 return A64DOpcode::format();
619 return A64DOpcode::format();
623 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
624 return A64DOpcode::format();
627 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
628 return A64DOpcode::format();
631 return A64DOpcode::format();
633 if ((opNum() < 0x4) || (opNum() > 0x5))
634 return A64DOpcode::format();
638 appendInstructionName(opName());
639 if ((opNum() >= 0x4) && (opNum() <= 0x7)) {
640 unsigned srcRegisterSize
= type() ^ 0x2; // 0:s, 1:d & 3:h
641 unsigned destRegisterSize
= (opNum() & 0x3) ^ 0x2;
642 appendFPRegisterName(rd(), destRegisterSize
);
644 appendFPRegisterName(rn(), srcRegisterSize
);
646 unsigned registerSize
= type() + 2;
647 appendFPRegisterName(rd(), registerSize
);
649 appendFPRegisterName(rn(), registerSize
);
652 return m_formatBuffer
;
655 const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames
[16] = {
656 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
659 const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
662 return A64DOpcode::format();
665 return A64DOpcode::format();
668 return A64DOpcode::format();
671 return A64DOpcode::format();
673 appendInstructionName(opName());
674 unsigned registerSize
= type() + 2;
675 appendFPRegisterName(rd(), registerSize
);
677 appendFPRegisterName(rn(), registerSize
);
679 appendFPRegisterName(rm(), registerSize
);
681 return m_formatBuffer
;
684 const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames
[4] = {
685 "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
688 const char* A64DOpcodeFloatingFixedPointConversions::format()
691 return A64DOpcode::format();
694 return A64DOpcode::format();
697 return A64DOpcode::format();
699 if (!(rmode() & 0x1) && !(opcode() & 0x6))
700 return A64DOpcode::format();
702 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
703 return A64DOpcode::format();
705 if (!(rmode() & 0x2) && !(opcode() & 0x6))
706 return A64DOpcode::format();
708 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
709 return A64DOpcode::format();
711 if (!is64Bit() && scale() >= 32)
712 return A64DOpcode::format();
714 appendInstructionName(opName());
715 unsigned FPRegisterSize
= type() + 2;
716 bool destIsFP
= !rmode();
719 appendFPRegisterName(rd(), FPRegisterSize
);
721 appendRegisterName(rn(), is64Bit());
723 appendRegisterName(rd(), is64Bit());
725 appendFPRegisterName(rn(), FPRegisterSize
);
728 appendUnsignedImmediate(64 - scale());
730 return m_formatBuffer
;
733 const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames
[32] = {
734 "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov",
735 "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov",
736 "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0,
737 "fcvtzs", "fcvtzu", 0, 0, 0, 0, 0, 0
740 const char* A64DOpcodeFloatingPointIntegerConversions::format()
743 return A64DOpcode::format();
746 return A64DOpcode::format();
748 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2)|| ((opcode() & 0x6) == 0x4)))
749 return A64DOpcode::format();
751 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
752 return A64DOpcode::format();
754 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
755 return A64DOpcode::format();
757 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
758 return A64DOpcode::format();
761 return A64DOpcode::format();
763 if ((opNum() & 0x1e) == 0xe) {
764 // Handle fmov to/from upper half of quad separately
765 if (!is64Bit() || (type() != 0x2))
766 return A64DOpcode::format();
768 appendInstructionName(opName());
769 if (opcode() & 0x1) {
771 bufferPrintf("V%u.D[1]", rd());
773 appendRegisterName(rn());
776 appendRegisterName(rd());
778 bufferPrintf("V%u.D[1]", rn());
781 return m_formatBuffer
;
784 appendInstructionName(opName());
785 unsigned FPRegisterSize
= type() + 2;
786 bool destIsFP
= ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
789 appendFPRegisterName(rd(), FPRegisterSize
);
791 appendRegisterName(rn(), is64Bit());
793 appendRegisterName(rd(), is64Bit());
795 appendFPRegisterName(rn(), FPRegisterSize
);
798 return m_formatBuffer
;
801 const char* const A64DOpcodeHint::s_opNames
[6] = {
802 "nop", "yield", "wfe", "wfi", "sev", "sevl"
805 const char* A64DOpcodeHint::format()
807 appendInstructionName(opName());
809 if (immediate7() > 5)
810 appendUnsignedImmediate(immediate7());
812 return m_formatBuffer
;
815 // A zero in an entry of the table means the instruction is Unallocated
816 const char* const A64DOpcodeLoadStore::s_opNames
[32] = {
817 "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
818 "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0,
819 "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0,
820 "str", "ldr", 0, 0, "str", "ldr", 0, 0
823 // A zero in an entry of the table means the instruction is Unallocated
824 const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames
[32] = {
825 "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0,
826 "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0,
827 "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0,
828 "sttr", "ldtr", 0, 0, 0, 0, 0, 0
831 // A zero in an entry of the table means the instruction is Unallocated
832 const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames
[32] = {
833 "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur",
834 "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0,
835 "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0,
836 "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0
839 const char* A64DOpcodeLoadStoreImmediate::format()
841 const char* thisOpName
;
844 thisOpName
= opName();
846 thisOpName
= unscaledOpName();
848 thisOpName
= unprivilegedOpName();
851 return A64DOpcode::format();
853 appendInstructionName(thisOpName
);
855 appendFPRegisterName(rt(), size());
857 appendRegisterName(rt(), is64BitRT());
859 appendCharacter('[');
860 appendSPOrRegisterName(rn());
863 case 0: // Unscaled Immediate
866 appendSignedImmediate(immediate9());
868 appendCharacter(']');
870 case 1: // Immediate Post-Indexed
871 appendCharacter(']');
874 appendSignedImmediate(immediate9());
877 case 2: // Unprivileged
880 appendSignedImmediate(immediate9());
882 appendCharacter(']');
884 case 3: // Immediate Pre-Indexed
887 appendSignedImmediate(immediate9());
889 appendCharacter(']');
890 appendCharacter('!');
894 return m_formatBuffer
;
897 const char* A64DOpcodeLoadStoreRegisterOffset::format()
899 const char* thisOpName
= opName();
902 return A64DOpcode::format();
904 if (!(option() & 0x2))
905 return A64DOpcode::format();
907 appendInstructionName(thisOpName
);
910 appendFPRegisterName(rt(), size());
911 scale
= ((opc() & 2)<<1) | size();
913 appendRegisterName(rt(), is64BitRT());
917 appendCharacter('[');
918 appendSPOrRegisterName(rn());
920 appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
922 unsigned shift
= sBit() ? scale
: 0;
924 if (option() == 0x3) {
927 appendString("lsl ");
928 appendUnsignedImmediate(shift
);
932 appendString(optionName());
934 appendUnsignedImmediate(shift
);
937 appendCharacter(']');
939 return m_formatBuffer
;
942 const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
944 const char* thisOpName
= opName();
947 return A64DOpcode::format();
949 appendInstructionName(thisOpName
);
952 appendFPRegisterName(rt(), size());
953 scale
= ((opc() & 2)<<1) | size();
955 appendRegisterName(rt(), is64BitRT());
959 appendCharacter('[');
960 appendSPOrRegisterName(rn());
964 appendUnsignedImmediate(immediate12() << scale
);
967 appendCharacter(']');
969 return m_formatBuffer
;
972 // A zero in an entry of the table means the instruction is Unallocated
973 const char* const A64DOpcodeLogical::s_opNames
[8] = {
974 "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics"
977 const char* A64DOpcodeLogicalShiftedRegister::format()
979 if (!is64Bit() && immediate6() & 0x20)
980 return A64DOpcode::format();
983 appendInstructionName("tst");
986 appendInstructionName("mov");
988 appendInstructionName(opName(opNumber()));
989 appendSPOrRegisterName(rd(), is64Bit());
994 appendRegisterName(rn(), is64Bit());
998 appendZROrRegisterName(rm(), is64Bit());
1001 appendShiftType(shift());
1002 appendUnsignedImmediate(immediate6());
1005 return m_formatBuffer
;
1008 static unsigned highestBitSet(unsigned value
)
1010 unsigned result
= 0;
1018 static uint64_t rotateRight(uint64_t value
, unsigned width
, unsigned shift
)
1020 uint64_t result
= value
;
1023 result
= (value
>> (shift
% width
)) | (value
<< (width
- shift
));
1028 static uint64_t replicate(uint64_t value
, unsigned width
)
1030 uint64_t result
= 0;
1032 for (unsigned totalBits
= 0; totalBits
< 64; totalBits
+= width
)
1033 result
= (result
<< width
) | value
;
1038 const char* A64DOpcodeLogicalImmediate::format()
1040 if (!is64Bit() && nBit())
1041 return A64DOpcode::format();
1043 unsigned len
= highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
1044 unsigned levels
= (1 << len
) - 1; // len number of 1 bits starting at LSB
1046 if ((immediateS() & levels
) == levels
)
1047 return A64DOpcode::format();
1049 unsigned r
= immediateR() & levels
;
1050 unsigned s
= immediateS() & levels
;
1051 unsigned eSize
= 1 << len
;
1052 uint64_t pattern
= rotateRight((1ull << (s
+ 1)) - 1, eSize
, r
);
1054 uint64_t immediate
= replicate(pattern
, eSize
);
1057 immediate
&= 0xffffffffull
;
1060 appendInstructionName("tst");
1063 appendInstructionName("mov");
1065 appendInstructionName(opName(opNumber()));
1066 appendRegisterName(rd(), is64Bit());
1070 appendRegisterName(rn(), is64Bit());
1073 appendUnsignedImmediate64(immediate
);
1075 return m_formatBuffer
;
1078 const char* const A64DOpcodeMoveWide::s_opNames
[4] = { "movn", "", "movz", "movk" };
1080 const char* A64DOpcodeMoveWide::format()
1083 return A64DOpcode::format();
1084 if (!size() && hw() >= 2)
1085 return A64DOpcode::format();
1087 appendInstructionName(opName());
1088 appendRegisterName(rd(), is64Bit());
1090 appendUnsignedImmediate(immediate16());
1093 appendShiftAmount(hw());
1096 return m_formatBuffer
;
1099 const char* A64DOpcodeTestAndBranchImmediate::format()
1101 appendInstructionName(opBit() ? "tbnz" : "tbz");
1102 appendRegisterName(rt());
1104 appendUnsignedImmediate(bitNumber());
1106 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate14()));
1107 return m_formatBuffer
;
1110 const char* A64DOpcodeUnconditionalBranchImmediate::format()
1112 appendInstructionName(op() ? "bl" : "b");
1113 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate26()));
1114 return m_formatBuffer
;
1117 const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames
[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
1119 const char* A64DOpcodeUnconditionalBranchRegister::format()
1121 unsigned opcValue
= opc();
1122 if (opcValue
== 3 || opcValue
> 5)
1123 return A64DOpcode::format();
1124 if (((opcValue
& 0xe) == 0x4) && rn() != 0x1f)
1125 return A64DOpcode::format();
1126 appendInstructionName(opName());
1128 appendRegisterName(rn());
1129 return m_formatBuffer
;
1132 } } // namespace JSC::ARM64Disassembler