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.
26 #define __STDC_FORMAT_MACROS
29 #if USE(ARM64_DISASSEMBLER)
31 #include "A64DOpcode.h"
37 namespace JSC
{ namespace ARM64Disassembler
{
39 A64DOpcode::OpcodeGroup
* A64DOpcode::opcodeTable
[32];
41 const char* const A64DOpcode::s_conditionNames
[16] = {
42 "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
43 "hi", "ls", "ge", "lt", "gt", "le", "al", "ne"
46 const char* const A64DOpcode::s_optionName
[8] = {
47 "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"
50 const char* const A64DOpcode::s_shiftNames
[4] = {
51 "lsl", "lsr", "asl", "ror"
54 const char A64DOpcode::s_FPRegisterPrefix
[5] = {
55 'b', 'h', 's', 'd', 'q'
58 struct OpcodeGroupInitializer
{
59 unsigned m_opcodeGroupNumber
;
62 const char* (*m_format
)(A64DOpcode
*);
65 #define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
66 { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
68 static OpcodeGroupInitializer opcodeGroupList
[] = {
69 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair
),
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(0x16, A64DOpcodeUnconditionalBranchImmediate
),
88 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister
),
89 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate
),
90 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate
),
91 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister
),
92 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate
),
93 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate
),
94 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset
),
95 OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate
),
96 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect
),
97 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source
),
98 OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source
),
99 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate
),
100 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset
),
101 OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate
),
102 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare
),
103 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source
),
104 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source
),
105 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions
),
106 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions
),
109 bool A64DOpcode::s_initialized
= false;
111 void A64DOpcode::init()
116 OpcodeGroup
* lastGroups
[32];
118 for (unsigned i
= 0; i
< 32; i
++) {
123 for (unsigned i
= 0; i
< sizeof(opcodeGroupList
) / sizeof(struct OpcodeGroupInitializer
); i
++) {
124 OpcodeGroup
* newOpcodeGroup
= new OpcodeGroup(opcodeGroupList
[i
].m_mask
, opcodeGroupList
[i
].m_pattern
, opcodeGroupList
[i
].m_format
);
125 uint32_t opcodeGroupNumber
= opcodeGroupList
[i
].m_opcodeGroupNumber
;
127 if (!opcodeTable
[opcodeGroupNumber
])
128 opcodeTable
[opcodeGroupNumber
] = newOpcodeGroup
;
130 lastGroups
[opcodeGroupNumber
]->setNext(newOpcodeGroup
);
131 lastGroups
[opcodeGroupNumber
] = newOpcodeGroup
;
134 s_initialized
= true;
137 void A64DOpcode::setPCAndOpcode(uint32_t* newPC
, uint32_t newOpcode
)
140 m_opcode
= newOpcode
;
142 m_formatBuffer
[0] = '\0';
145 const char* A64DOpcode::disassemble(uint32_t* currentPC
)
147 setPCAndOpcode(currentPC
, *currentPC
);
149 OpcodeGroup
* opGroup
= opcodeTable
[opcodeGroupNumber(m_opcode
)];
152 if (opGroup
->matches(m_opcode
))
153 return opGroup
->format(this);
154 opGroup
= opGroup
->next();
157 return A64DOpcode::format();
160 void A64DOpcode::bufferPrintf(const char* format
, ...)
162 if (m_bufferOffset
>= bufferSize
)
166 va_start(argList
, format
);
168 m_bufferOffset
+= vsnprintf(m_formatBuffer
+ m_bufferOffset
, bufferSize
- m_bufferOffset
, format
, argList
);
173 const char* A64DOpcode::format()
175 bufferPrintf(" .long %08x", m_opcode
);
176 return m_formatBuffer
;
179 void A64DOpcode::appendRegisterName(unsigned registerNumber
, bool is64Bit
)
181 if (registerNumber
== 29) {
182 bufferPrintf(is64Bit
? "fp" : "wfp");
186 if (registerNumber
== 30) {
187 bufferPrintf(is64Bit
? "lr" : "wlr");
191 bufferPrintf("%c%u", is64Bit
? 'x' : 'w', registerNumber
);
194 void A64DOpcode::appendFPRegisterName(unsigned registerNumber
, unsigned registerSize
)
196 bufferPrintf("%c%u", FPRegisterPrefix(registerSize
), registerNumber
);
199 const char* const A64DOpcodeAddSubtract::s_opNames
[4] = { "add", "adds", "sub", "subs" };
201 const char* A64DOpcodeAddSubtractImmediate::format()
204 appendInstructionName(cmpName());
207 appendInstructionName("mov");
209 appendInstructionName(opName());
210 appendSPOrRegisterName(rd(), is64Bit());
213 appendSPOrRegisterName(rn(), is64Bit());
217 appendUnsignedImmediate(immed12());
220 appendString(shift() == 1 ? "lsl" : "reserved");
223 return m_formatBuffer
;
226 const char* A64DOpcodeAddSubtractExtendedRegister::format()
228 if (immediate3() > 4)
229 return A64DOpcode::format();
232 appendInstructionName(cmpName());
234 appendInstructionName(opName());
235 appendSPOrRegisterName(rd(), is64Bit());
238 appendSPOrRegisterName(rn(), is64Bit());
240 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
242 if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
245 appendString(optionName());
247 appendCharacter(' ');
248 appendUnsignedImmediate(immediate3());
251 return m_formatBuffer
;
254 const char* A64DOpcodeAddSubtractShiftedRegister::format()
256 if (!is64Bit() && immediate6() & 0x20)
257 return A64DOpcode::format();
260 return A64DOpcode::format();
263 appendInstructionName(cmpName());
266 appendInstructionName(cmpName());
268 appendInstructionName(opName());
269 appendSPOrRegisterName(rd(), is64Bit());
273 appendRegisterName(rn(), is64Bit());
276 appendZROrRegisterName(rm(), is64Bit());
279 appendShiftType(shift());
280 appendUnsignedImmediate(immediate6());
283 return m_formatBuffer
;
286 const char* const A64DOpcodeBitfield::s_opNames
[3] = { "sbfm", "bfm", "ubfm" };
287 const char* const A64DOpcodeBitfield::s_extendPseudoOpNames
[3][3] = {
288 { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
289 const char* const A64DOpcodeBitfield::s_insertOpNames
[3] = { "sbfiz", "bfi", "ubfiz" };
290 const char* const A64DOpcodeBitfield::s_extractOpNames
[3] = { "sbfx", "bf", "ubfx" };
292 const char* A64DOpcodeBitfield::format()
295 return A64DOpcode::format();
297 if (is64Bit() != nBit())
298 return A64DOpcode::format();
300 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
301 return A64DOpcode::format();
303 if (!(opc() & 0x1) && !immediateR()) {
304 // [un]signed {btye,half-word,word} extend
305 bool isSTXType
= false;
306 if (immediateS() == 7) {
307 appendInstructionName(extendPseudoOpNames(0));
309 } else if (immediateS() == 15) {
310 appendInstructionName(extendPseudoOpNames(1));
312 } else if (immediateS() == 31 && is64Bit()) {
313 appendInstructionName(extendPseudoOpNames(2));
318 appendRegisterName(rd(), is64Bit());
320 appendRegisterName(rn(), false);
322 return m_formatBuffer
;
326 if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
328 appendInstructionName("lsl");
329 appendRegisterName(rd(), is64Bit());
331 appendRegisterName(rn(), is64Bit());
333 appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
335 return m_formatBuffer
;
336 } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
338 appendInstructionName(!opc() ? "ars" : "lsr");
340 appendRegisterName(rd(), is64Bit());
342 appendRegisterName(rn(), is64Bit());
344 appendUnsignedImmediate(immediateR());
346 return m_formatBuffer
;
347 } else if (immediateS() < immediateR()) {
349 appendInstructionName(insertOpNames());
351 appendRegisterName(rd(), is64Bit());
353 appendRegisterName(rn(), is64Bit());
355 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
357 appendUnsignedImmediate(immediateS() + 1);
359 return m_formatBuffer
;
362 appendInstructionName(extractOpNames());
364 appendRegisterName(rd(), is64Bit());
366 appendRegisterName(rn(), is64Bit());
368 appendUnsignedImmediate(immediateR());
370 appendUnsignedImmediate(immediateS() - immediateR() + 1);
372 return m_formatBuffer
;
375 appendInstructionName(opName());
376 appendRegisterName(rd(), is64Bit());
378 appendRegisterName(rn(), is64Bit());
380 appendUnsignedImmediate(immediateR());
382 appendUnsignedImmediate(immediateS());
384 return m_formatBuffer
;
387 const char* A64DOpcodeCompareAndBranchImmediate::format()
389 appendInstructionName(opBit() ? "cbnz" : "cbz");
390 appendRegisterName(rt(), is64Bit());
392 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate19()));
393 return m_formatBuffer
;
396 const char* A64DOpcodeConditionalBranchImmediate::format()
398 bufferPrintf(" b.%-5.5s", conditionName(condition()));
399 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate19()));
400 return m_formatBuffer
;
403 const char* const A64DOpcodeConditionalSelect::s_opNames
[4] = {
404 "csel", "csinc", "csinv", "csneg"
407 const char* A64DOpcodeConditionalSelect::format()
410 return A64DOpcode::format();
413 return A64DOpcode::format();
415 if (rn() == rm() && (opNum() == 1 || opNum() == 2)) {
417 appendInstructionName((opNum() == 1) ? "cset" : "csetm");
418 appendRegisterName(rd(), is64Bit());
420 appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
421 appendRegisterName(rd(), is64Bit());
423 appendZROrRegisterName(rn(), is64Bit());
426 appendString(conditionName(condition() ^ 0x1));
428 return m_formatBuffer
;
431 appendInstructionName(opName());
432 appendRegisterName(rd(), is64Bit());
434 appendZROrRegisterName(rn(), is64Bit());
436 appendZROrRegisterName(rm(), is64Bit());
438 appendString(conditionName(condition()));
440 return m_formatBuffer
;
444 const char* const A64DOpcodeDataProcessing2Source::s_opNames
[8] = {
445 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions
448 const char* A64DOpcodeDataProcessing2Source::format()
451 return A64DOpcode::format();
453 if (!(opCode() & 0x3e))
454 return A64DOpcode::format();
457 return A64DOpcode::format();
459 if ((opCode() & 0x34) == 0x4)
460 return A64DOpcode::format();
462 appendInstructionName(opName());
463 appendRegisterName(rd(), is64Bit());
465 appendRegisterName(rn(), is64Bit());
467 appendRegisterName(rm(), is64Bit());
469 return m_formatBuffer
;
472 const char* const A64DOpcodeDataProcessing3Source::s_opNames
[16] = {
473 "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0,
474 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0
477 const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames
[16] = {
478 "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0,
479 0, 0, "umull", "umnegl", "umulh", 0, 0, 0
482 const char* A64DOpcodeDataProcessing3Source::format()
485 return A64DOpcode::format();
488 return A64DOpcode::format();
490 if (!is64Bit() && opNum() > 1)
491 return A64DOpcode::format();
494 return A64DOpcode::format();
496 appendInstructionName(opName());
497 appendRegisterName(rd(), is64Bit());
499 bool srcOneAndTwoAre64Bit
= is64Bit() & !(opNum() & 0x2);
500 appendRegisterName(rn(), srcOneAndTwoAre64Bit
);
502 appendRegisterName(rm(), srcOneAndTwoAre64Bit
);
504 if ((ra() != 31) || !(opNum() & 0x4)) {
506 appendRegisterName(ra(), is64Bit());
509 return m_formatBuffer
;
512 const char* A64OpcodeExceptionGeneration::format()
514 const char* opname
= 0;
517 case 0x0: // SVC, HVC & SMC
555 return A64DOpcode::format();
557 appendInstructionName(opname
);
558 appendUnsignedImmediate(immediate16());
559 return m_formatBuffer
;
562 const char* A64DOpcodeExtract::format()
564 if (!op21() || !o0Bit())
565 return A64DOpcode::format();
567 if (is64Bit() != nBit())
568 return A64DOpcode::format();
570 if (is64Bit() && (immediateS() & 0x20))
571 return A64DOpcode::format();
573 const char* opName
= (rn() == rm()) ? "ror" : "extr";
575 appendInstructionName(opName
);
576 appendRegisterName(rd(), is64Bit());
578 appendRegisterName(rn(), is64Bit());
580 appendRegisterName(rm(), is64Bit());
582 appendUnsignedImmediate(immediateS());
584 return m_formatBuffer
;
587 const char* A64DOpcodeFloatingPointCompare::format()
590 return A64DOpcode::format();
593 return A64DOpcode::format();
596 return A64DOpcode::format();
599 return A64DOpcode::format();
602 return A64DOpcode::format();
604 appendInstructionName(opName());
605 unsigned registerSize
= type() + 2;
606 appendFPRegisterName(rn(), registerSize
);
609 bufferPrintf("#0.0");
611 appendFPRegisterName(rm(), registerSize
);
613 return m_formatBuffer
;
616 const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames
[16] = {
617 "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
618 "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
621 const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
624 return A64DOpcode::format();
627 return A64DOpcode::format();
630 return A64DOpcode::format();
634 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
635 return A64DOpcode::format();
638 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
639 return A64DOpcode::format();
642 return A64DOpcode::format();
644 if ((opNum() < 0x4) || (opNum() > 0x5))
645 return A64DOpcode::format();
649 appendInstructionName(opName());
650 if ((opNum() >= 0x4) && (opNum() <= 0x7)) {
651 unsigned srcRegisterSize
= type() ^ 0x2; // 0:s, 1:d & 3:h
652 unsigned destRegisterSize
= (opNum() & 0x3) ^ 0x2;
653 appendFPRegisterName(rd(), destRegisterSize
);
655 appendFPRegisterName(rn(), srcRegisterSize
);
657 unsigned registerSize
= type() + 2;
658 appendFPRegisterName(rd(), registerSize
);
660 appendFPRegisterName(rn(), registerSize
);
663 return m_formatBuffer
;
666 const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames
[16] = {
667 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
670 const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
673 return A64DOpcode::format();
676 return A64DOpcode::format();
679 return A64DOpcode::format();
682 return A64DOpcode::format();
684 appendInstructionName(opName());
685 unsigned registerSize
= type() + 2;
686 appendFPRegisterName(rd(), registerSize
);
688 appendFPRegisterName(rn(), registerSize
);
690 appendFPRegisterName(rm(), registerSize
);
692 return m_formatBuffer
;
695 const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames
[4] = {
696 "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
699 const char* A64DOpcodeFloatingFixedPointConversions::format()
702 return A64DOpcode::format();
705 return A64DOpcode::format();
708 return A64DOpcode::format();
710 if (!(rmode() & 0x1) && !(opcode() & 0x6))
711 return A64DOpcode::format();
713 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
714 return A64DOpcode::format();
716 if (!(rmode() & 0x2) && !(opcode() & 0x6))
717 return A64DOpcode::format();
719 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
720 return A64DOpcode::format();
722 if (!is64Bit() && scale() >= 32)
723 return A64DOpcode::format();
725 appendInstructionName(opName());
726 unsigned FPRegisterSize
= type() + 2;
727 bool destIsFP
= !rmode();
730 appendFPRegisterName(rd(), FPRegisterSize
);
732 appendRegisterName(rn(), is64Bit());
734 appendRegisterName(rd(), is64Bit());
736 appendFPRegisterName(rn(), FPRegisterSize
);
739 appendUnsignedImmediate(64 - scale());
741 return m_formatBuffer
;
744 const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames
[32] = {
745 "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov",
746 "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov",
747 "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0,
748 "fcvtzs", "fcvtzu", 0, 0, 0, 0, 0, 0
751 const char* A64DOpcodeFloatingPointIntegerConversions::format()
754 return A64DOpcode::format();
757 return A64DOpcode::format();
759 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4)))
760 return A64DOpcode::format();
762 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
763 return A64DOpcode::format();
765 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
766 return A64DOpcode::format();
768 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
769 return A64DOpcode::format();
772 return A64DOpcode::format();
774 if ((opNum() & 0x1e) == 0xe) {
775 // Handle fmov to/from upper half of quad separately
776 if (!is64Bit() || (type() != 0x2))
777 return A64DOpcode::format();
779 appendInstructionName(opName());
780 if (opcode() & 0x1) {
782 bufferPrintf("V%u.D[1]", rd());
784 appendRegisterName(rn());
787 appendRegisterName(rd());
789 bufferPrintf("V%u.D[1]", rn());
792 return m_formatBuffer
;
795 appendInstructionName(opName());
796 unsigned FPRegisterSize
= type() + 2;
797 bool destIsFP
= ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
800 appendFPRegisterName(rd(), FPRegisterSize
);
802 appendRegisterName(rn(), is64Bit());
804 appendRegisterName(rd(), is64Bit());
806 appendFPRegisterName(rn(), FPRegisterSize
);
809 return m_formatBuffer
;
812 const char* const A64DOpcodeHint::s_opNames
[6] = {
813 "nop", "yield", "wfe", "wfi", "sev", "sevl"
816 const char* A64DOpcodeHint::format()
818 appendInstructionName(opName());
820 if (immediate7() > 5)
821 appendUnsignedImmediate(immediate7());
823 return m_formatBuffer
;
826 // A zero in an entry of the table means the instruction is Unallocated
827 const char* const A64DOpcodeLoadStore::s_opNames
[32] = {
828 "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
829 "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0,
830 "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0,
831 "str", "ldr", 0, 0, "str", "ldr", 0, 0
834 // A zero in an entry of the table means the instruction is Unallocated
835 const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames
[32] = {
836 "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0,
837 "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0,
838 "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0,
839 "sttr", "ldtr", 0, 0, 0, 0, 0, 0
842 // A zero in an entry of the table means the instruction is Unallocated
843 const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames
[32] = {
844 "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur",
845 "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0,
846 "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0,
847 "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0
850 const char* A64DOpcodeLoadStoreImmediate::format()
852 const char* thisOpName
;
855 thisOpName
= opName();
857 thisOpName
= unscaledOpName();
859 thisOpName
= unprivilegedOpName();
862 return A64DOpcode::format();
864 appendInstructionName(thisOpName
);
866 appendFPRegisterName(rt(), size());
868 appendRegisterName(rt(), is64BitRT());
870 appendCharacter('[');
871 appendSPOrRegisterName(rn());
874 case 0: // Unscaled Immediate
877 appendSignedImmediate(immediate9());
879 appendCharacter(']');
881 case 1: // Immediate Post-Indexed
882 appendCharacter(']');
885 appendSignedImmediate(immediate9());
888 case 2: // Unprivileged
891 appendSignedImmediate(immediate9());
893 appendCharacter(']');
895 case 3: // Immediate Pre-Indexed
898 appendSignedImmediate(immediate9());
900 appendCharacter(']');
901 appendCharacter('!');
905 return m_formatBuffer
;
908 const char* A64DOpcodeLoadStoreRegisterOffset::format()
910 const char* thisOpName
= opName();
913 return A64DOpcode::format();
915 if (!(option() & 0x2))
916 return A64DOpcode::format();
918 appendInstructionName(thisOpName
);
921 appendFPRegisterName(rt(), size());
922 scale
= ((opc() & 2)<<1) | size();
924 appendRegisterName(rt(), is64BitRT());
928 appendCharacter('[');
929 appendSPOrRegisterName(rn());
931 appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
933 unsigned shift
= sBit() ? scale
: 0;
935 if (option() == 0x3) {
938 appendString("lsl ");
939 appendUnsignedImmediate(shift
);
943 appendString(optionName());
945 appendUnsignedImmediate(shift
);
948 appendCharacter(']');
950 return m_formatBuffer
;
953 const char* A64DOpcodeLoadStoreRegisterPair::opName()
955 if (!vBit() && lBit() && size() == 0x1)
962 const char* A64DOpcodeLoadStoreRegisterPair::format()
964 const char* thisOpName
= opName();
967 return A64DOpcode::format();
969 if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
970 return A64DOpcode::format();
972 if ((offsetMode() == 0x1) && !vBit() && !lBit())
973 return A64DOpcode::format();
975 appendInstructionName(thisOpName
);
976 unsigned offsetShift
;
978 appendFPRegisterName(rt(), size());
980 appendFPRegisterName(rt2(), size());
981 offsetShift
= size() + 2;
983 appendRegisterName(rt(), is64Bit());
985 appendRegisterName(rt2(), is64Bit());
986 offsetShift
= (size() >> 1) + 2;
990 appendCharacter('[');
991 appendSPOrRegisterName(rn());
993 int offset
= immediate7() << offsetShift
;
995 if (offsetMode() == 1) {
996 appendCharacter(']');
998 appendSignedImmediate(offset
);
1001 appendSignedImmediate(offset
);
1002 appendCharacter(']');
1003 if (offsetMode() == 0x3)
1004 appendCharacter('!');
1007 return m_formatBuffer
;
1010 const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
1012 const char* thisOpName
= opName();
1015 return A64DOpcode::format();
1017 appendInstructionName(thisOpName
);
1020 appendFPRegisterName(rt(), size());
1021 scale
= ((opc() & 2)<<1) | size();
1023 appendRegisterName(rt(), is64BitRT());
1027 appendCharacter('[');
1028 appendSPOrRegisterName(rn());
1030 if (immediate12()) {
1032 appendUnsignedImmediate(immediate12() << scale
);
1035 appendCharacter(']');
1037 return m_formatBuffer
;
1040 // A zero in an entry of the table means the instruction is Unallocated
1041 const char* const A64DOpcodeLogical::s_opNames
[8] = {
1042 "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics"
1045 const char* A64DOpcodeLogicalShiftedRegister::format()
1047 if (!is64Bit() && immediate6() & 0x20)
1048 return A64DOpcode::format();
1051 appendInstructionName("tst");
1054 appendInstructionName("mov");
1056 appendInstructionName(opName(opNumber()));
1057 appendSPOrRegisterName(rd(), is64Bit());
1062 appendRegisterName(rn(), is64Bit());
1066 appendZROrRegisterName(rm(), is64Bit());
1069 appendShiftType(shift());
1070 appendUnsignedImmediate(immediate6());
1073 return m_formatBuffer
;
1076 static unsigned highestBitSet(unsigned value
)
1078 unsigned result
= 0;
1086 static uint64_t rotateRight(uint64_t value
, unsigned width
, unsigned shift
)
1088 uint64_t result
= value
;
1091 result
= (value
>> (shift
% width
)) | (value
<< (width
- shift
));
1096 static uint64_t replicate(uint64_t value
, unsigned width
)
1098 uint64_t result
= 0;
1100 for (unsigned totalBits
= 0; totalBits
< 64; totalBits
+= width
)
1101 result
= (result
<< width
) | value
;
1106 const char* A64DOpcodeLogicalImmediate::format()
1108 if (!is64Bit() && nBit())
1109 return A64DOpcode::format();
1111 unsigned len
= highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
1112 unsigned levels
= (1 << len
) - 1; // len number of 1 bits starting at LSB
1114 if ((immediateS() & levels
) == levels
)
1115 return A64DOpcode::format();
1117 unsigned r
= immediateR() & levels
;
1118 unsigned s
= immediateS() & levels
;
1119 unsigned eSize
= 1 << len
;
1120 uint64_t pattern
= rotateRight((1ull << (s
+ 1)) - 1, eSize
, r
);
1122 uint64_t immediate
= replicate(pattern
, eSize
);
1125 immediate
&= 0xffffffffull
;
1128 appendInstructionName("tst");
1131 appendInstructionName("mov");
1133 appendInstructionName(opName(opNumber()));
1134 appendRegisterName(rd(), is64Bit());
1138 appendRegisterName(rn(), is64Bit());
1141 appendUnsignedImmediate64(immediate
);
1143 return m_formatBuffer
;
1146 const char* const A64DOpcodeMoveWide::s_opNames
[4] = { "movn", "", "movz", "movk" };
1148 const char* A64DOpcodeMoveWide::format()
1151 return A64DOpcode::format();
1152 if (!size() && hw() >= 2)
1153 return A64DOpcode::format();
1155 appendInstructionName(opName());
1156 appendRegisterName(rd(), is64Bit());
1158 appendUnsignedImmediate(immediate16());
1161 appendShiftAmount(hw());
1164 return m_formatBuffer
;
1167 const char* A64DOpcodeTestAndBranchImmediate::format()
1169 appendInstructionName(opBit() ? "tbnz" : "tbz");
1170 appendRegisterName(rt());
1172 appendUnsignedImmediate(bitNumber());
1174 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate14()));
1175 return m_formatBuffer
;
1178 const char* A64DOpcodeUnconditionalBranchImmediate::format()
1180 appendInstructionName(op() ? "bl" : "b");
1181 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate26()));
1182 return m_formatBuffer
;
1185 const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames
[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
1187 const char* A64DOpcodeUnconditionalBranchRegister::format()
1189 unsigned opcValue
= opc();
1190 if (opcValue
== 3 || opcValue
> 5)
1191 return A64DOpcode::format();
1192 if (((opcValue
& 0xe) == 0x4) && rn() != 0x1f)
1193 return A64DOpcode::format();
1194 appendInstructionName(opName());
1196 appendRegisterName(rn());
1197 return m_formatBuffer
;
1200 } } // namespace JSC::ARM64Disassembler
1202 #endif // USE(ARM64_DISASSEMBLER)