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.
27 #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"
46 const char* const A64DOpcode::s_shiftNames
[4] = {
47 "lsl", "lsr", "asl", "ror"
50 const char A64DOpcode::s_FPRegisterPrefix
[5] = {
51 'b', 'h', 's', 'd', 'q'
54 struct OpcodeGroupInitializer
{
55 unsigned m_opcodeGroupNumber
;
58 const char* (*m_format
)(A64DOpcode
*);
61 #define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
62 { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
64 static OpcodeGroupInitializer opcodeGroupList
[] = {
65 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair
),
66 OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair
),
67 OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister
),
68 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister
),
69 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister
),
70 OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate
),
71 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide
),
72 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate
),
73 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield
),
74 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract
),
75 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate
),
76 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate
),
77 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate
),
78 OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration
),
79 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate
),
80 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate
),
81 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate
),
82 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint
),
83 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate
),
84 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister
),
85 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate
),
86 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate
),
87 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister
),
88 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate
),
89 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate
),
90 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset
),
91 OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate
),
92 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect
),
93 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source
),
94 OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source
),
95 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate
),
96 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset
),
97 OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate
),
98 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare
),
99 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source
),
100 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source
),
101 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions
),
102 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions
),
105 bool A64DOpcode::s_initialized
= false;
107 void A64DOpcode::init()
112 OpcodeGroup
* lastGroups
[32];
114 for (unsigned i
= 0; i
< 32; i
++) {
119 for (unsigned i
= 0; i
< sizeof(opcodeGroupList
) / sizeof(struct OpcodeGroupInitializer
); i
++) {
120 OpcodeGroup
* newOpcodeGroup
= new OpcodeGroup(opcodeGroupList
[i
].m_mask
, opcodeGroupList
[i
].m_pattern
, opcodeGroupList
[i
].m_format
);
121 uint32_t opcodeGroupNumber
= opcodeGroupList
[i
].m_opcodeGroupNumber
;
123 if (!opcodeTable
[opcodeGroupNumber
])
124 opcodeTable
[opcodeGroupNumber
] = newOpcodeGroup
;
126 lastGroups
[opcodeGroupNumber
]->setNext(newOpcodeGroup
);
127 lastGroups
[opcodeGroupNumber
] = newOpcodeGroup
;
130 s_initialized
= true;
133 void A64DOpcode::setPCAndOpcode(uint32_t* newPC
, uint32_t newOpcode
)
136 m_opcode
= newOpcode
;
138 m_formatBuffer
[0] = '\0';
141 const char* A64DOpcode::disassemble(uint32_t* currentPC
)
143 setPCAndOpcode(currentPC
, *currentPC
);
145 OpcodeGroup
* opGroup
= opcodeTable
[opcodeGroupNumber(m_opcode
)];
148 if (opGroup
->matches(m_opcode
))
149 return opGroup
->format(this);
150 opGroup
= opGroup
->next();
153 return A64DOpcode::format();
156 void A64DOpcode::bufferPrintf(const char* format
, ...)
158 if (m_bufferOffset
>= bufferSize
)
162 va_start(argList
, format
);
164 m_bufferOffset
+= vsnprintf(m_formatBuffer
+ m_bufferOffset
, bufferSize
- m_bufferOffset
, format
, argList
);
169 const char* A64DOpcode::format()
171 bufferPrintf(" .long %08x", m_opcode
);
172 return m_formatBuffer
;
175 void A64DOpcode::appendRegisterName(unsigned registerNumber
, bool is64Bit
)
177 if (registerNumber
== 29) {
178 bufferPrintf(is64Bit
? "fp" : "wfp");
182 if (registerNumber
== 30) {
183 bufferPrintf(is64Bit
? "lr" : "wlr");
187 bufferPrintf("%c%u", is64Bit
? 'x' : 'w', registerNumber
);
190 void A64DOpcode::appendFPRegisterName(unsigned registerNumber
, unsigned registerSize
)
192 bufferPrintf("%c%u", FPRegisterPrefix(registerSize
), registerNumber
);
195 const char* const A64DOpcodeAddSubtract::s_opNames
[4] = { "add", "adds", "sub", "subs" };
197 const char* A64DOpcodeAddSubtractImmediate::format()
200 appendInstructionName(cmpName());
203 appendInstructionName("mov");
205 appendInstructionName(opName());
206 appendSPOrRegisterName(rd(), is64Bit());
209 appendSPOrRegisterName(rn(), is64Bit());
213 appendUnsignedImmediate(immed12());
216 appendString(shift() == 1 ? "lsl" : "reserved");
219 return m_formatBuffer
;
222 const char* A64DOpcodeAddSubtractExtendedRegister::format()
224 if (immediate3() > 4)
225 return A64DOpcode::format();
228 appendInstructionName(cmpName());
230 appendInstructionName(opName());
231 appendSPOrRegisterName(rd(), is64Bit());
234 appendSPOrRegisterName(rn(), is64Bit());
236 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
238 if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
241 appendString(optionName());
243 appendCharacter(' ');
244 appendUnsignedImmediate(immediate3());
247 return m_formatBuffer
;
250 const char* A64DOpcodeAddSubtractShiftedRegister::format()
252 if (!is64Bit() && immediate6() & 0x20)
253 return A64DOpcode::format();
256 return A64DOpcode::format();
259 appendInstructionName(cmpName());
262 appendInstructionName(cmpName());
264 appendInstructionName(opName());
265 appendSPOrRegisterName(rd(), is64Bit());
269 appendRegisterName(rn(), is64Bit());
272 appendZROrRegisterName(rm(), is64Bit());
275 appendShiftType(shift());
276 appendUnsignedImmediate(immediate6());
279 return m_formatBuffer
;
282 const char* const A64DOpcodeBitfield::s_opNames
[3] = { "sbfm", "bfm", "ubfm" };
283 const char* const A64DOpcodeBitfield::s_extendPseudoOpNames
[3][3] = {
284 { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
285 const char* const A64DOpcodeBitfield::s_insertOpNames
[3] = { "sbfiz", "bfi", "ubfiz" };
286 const char* const A64DOpcodeBitfield::s_extractOpNames
[3] = { "sbfx", "bf", "ubfx" };
288 const char* A64DOpcodeBitfield::format()
291 return A64DOpcode::format();
293 if (is64Bit() != nBit())
294 return A64DOpcode::format();
296 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
297 return A64DOpcode::format();
299 if (!(opc() & 0x1) && !immediateR()) {
300 // [un]signed {btye,half-word,word} extend
301 bool isSTXType
= false;
302 if (immediateS() == 7) {
303 appendInstructionName(extendPseudoOpNames(0));
305 } else if (immediateS() == 15) {
306 appendInstructionName(extendPseudoOpNames(1));
308 } else if (immediateS() == 31 && is64Bit()) {
309 appendInstructionName(extendPseudoOpNames(2));
314 appendRegisterName(rd(), is64Bit());
316 appendRegisterName(rn(), false);
318 return m_formatBuffer
;
322 if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
324 appendInstructionName("lsl");
325 appendRegisterName(rd(), is64Bit());
327 appendRegisterName(rn(), is64Bit());
329 appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
331 return m_formatBuffer
;
332 } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
334 appendInstructionName(!opc() ? "ars" : "lsr");
336 appendRegisterName(rd(), is64Bit());
338 appendRegisterName(rn(), is64Bit());
340 appendUnsignedImmediate(immediateR());
342 return m_formatBuffer
;
343 } else if (immediateS() < immediateR()) {
345 appendInstructionName(insertOpNames());
347 appendRegisterName(rd(), is64Bit());
349 appendRegisterName(rn(), is64Bit());
351 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
353 appendUnsignedImmediate(immediateS() + 1);
355 return m_formatBuffer
;
358 appendInstructionName(extractOpNames());
360 appendRegisterName(rd(), is64Bit());
362 appendRegisterName(rn(), is64Bit());
364 appendUnsignedImmediate(immediateR());
366 appendUnsignedImmediate(immediateS() - immediateR() + 1);
368 return m_formatBuffer
;
371 appendInstructionName(opName());
372 appendRegisterName(rd(), is64Bit());
374 appendRegisterName(rn(), is64Bit());
376 appendUnsignedImmediate(immediateR());
378 appendUnsignedImmediate(immediateS());
380 return m_formatBuffer
;
383 const char* A64DOpcodeCompareAndBranchImmediate::format()
385 appendInstructionName(opBit() ? "cbnz" : "cbz");
386 appendRegisterName(rt(), is64Bit());
388 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate19()));
389 return m_formatBuffer
;
392 const char* A64DOpcodeConditionalBranchImmediate::format()
394 bufferPrintf(" b.%-5.5s", conditionName(condition()));
395 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate19()));
396 return m_formatBuffer
;
399 const char* const A64DOpcodeConditionalSelect::s_opNames
[4] = {
400 "csel", "csinc", "csinv", "csneg"
403 const char* A64DOpcodeConditionalSelect::format()
406 return A64DOpcode::format();
409 return A64DOpcode::format();
411 if (rn() == rm() && (opNum() == 1 || opNum() == 2)) {
413 appendInstructionName((opNum() == 1) ? "cset" : "csetm");
414 appendRegisterName(rd(), is64Bit());
416 appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
417 appendRegisterName(rd(), is64Bit());
419 appendZROrRegisterName(rn(), is64Bit());
422 appendString(conditionName(condition() ^ 0x1));
424 return m_formatBuffer
;
427 appendInstructionName(opName());
428 appendRegisterName(rd(), is64Bit());
430 appendZROrRegisterName(rn(), is64Bit());
432 appendZROrRegisterName(rm(), is64Bit());
434 appendString(conditionName(condition()));
436 return m_formatBuffer
;
440 const char* const A64DOpcodeDataProcessing2Source::s_opNames
[8] = {
441 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions
444 const char* A64DOpcodeDataProcessing2Source::format()
447 return A64DOpcode::format();
449 if (!(opCode() & 0x3e))
450 return A64DOpcode::format();
453 return A64DOpcode::format();
455 if ((opCode() & 0x34) == 0x4)
456 return A64DOpcode::format();
458 appendInstructionName(opName());
459 appendRegisterName(rd(), is64Bit());
461 appendRegisterName(rn(), is64Bit());
463 appendRegisterName(rm(), is64Bit());
465 return m_formatBuffer
;
468 const char* const A64DOpcodeDataProcessing3Source::s_opNames
[16] = {
469 "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0,
470 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0
473 const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames
[16] = {
474 "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0,
475 0, 0, "umull", "umnegl", "umulh", 0, 0, 0
478 const char* A64DOpcodeDataProcessing3Source::format()
481 return A64DOpcode::format();
484 return A64DOpcode::format();
486 if (!is64Bit() && opNum() > 1)
487 return A64DOpcode::format();
490 return A64DOpcode::format();
492 appendInstructionName(opName());
493 appendRegisterName(rd(), is64Bit());
495 bool srcOneAndTwoAre64Bit
= is64Bit() & !(opNum() & 0x2);
496 appendRegisterName(rn(), srcOneAndTwoAre64Bit
);
498 appendRegisterName(rm(), srcOneAndTwoAre64Bit
);
500 if ((ra() != 31) || !(opNum() & 0x4)) {
502 appendRegisterName(ra(), is64Bit());
505 return m_formatBuffer
;
508 const char* A64OpcodeExceptionGeneration::format()
510 const char* opname
= 0;
513 case 0x0: // SVC, HVC & SMC
551 return A64DOpcode::format();
553 appendInstructionName(opname
);
554 appendUnsignedImmediate(immediate16());
555 return m_formatBuffer
;
558 const char* A64DOpcodeExtract::format()
560 if (!op21() || !o0Bit())
561 return A64DOpcode::format();
563 if (is64Bit() != nBit())
564 return A64DOpcode::format();
566 if (is64Bit() && (immediateS() & 0x20))
567 return A64DOpcode::format();
569 const char* opName
= (rn() == rm()) ? "ror" : "extr";
571 appendInstructionName(opName
);
572 appendRegisterName(rd(), is64Bit());
574 appendRegisterName(rn(), is64Bit());
576 appendRegisterName(rm(), is64Bit());
578 appendUnsignedImmediate(immediateS());
580 return m_formatBuffer
;
583 const char* A64DOpcodeFloatingPointCompare::format()
586 return A64DOpcode::format();
589 return A64DOpcode::format();
592 return A64DOpcode::format();
595 return A64DOpcode::format();
598 return A64DOpcode::format();
600 appendInstructionName(opName());
601 unsigned registerSize
= type() + 2;
602 appendFPRegisterName(rn(), registerSize
);
605 bufferPrintf("#0.0");
607 appendFPRegisterName(rm(), registerSize
);
609 return m_formatBuffer
;
612 const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames
[16] = {
613 "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
614 "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
617 const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
620 return A64DOpcode::format();
623 return A64DOpcode::format();
626 return A64DOpcode::format();
630 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
631 return A64DOpcode::format();
634 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
635 return A64DOpcode::format();
638 return A64DOpcode::format();
640 if ((opNum() < 0x4) || (opNum() > 0x5))
641 return A64DOpcode::format();
645 appendInstructionName(opName());
646 if ((opNum() >= 0x4) && (opNum() <= 0x7)) {
647 unsigned srcRegisterSize
= type() ^ 0x2; // 0:s, 1:d & 3:h
648 unsigned destRegisterSize
= (opNum() & 0x3) ^ 0x2;
649 appendFPRegisterName(rd(), destRegisterSize
);
651 appendFPRegisterName(rn(), srcRegisterSize
);
653 unsigned registerSize
= type() + 2;
654 appendFPRegisterName(rd(), registerSize
);
656 appendFPRegisterName(rn(), registerSize
);
659 return m_formatBuffer
;
662 const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames
[16] = {
663 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
666 const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
669 return A64DOpcode::format();
672 return A64DOpcode::format();
675 return A64DOpcode::format();
678 return A64DOpcode::format();
680 appendInstructionName(opName());
681 unsigned registerSize
= type() + 2;
682 appendFPRegisterName(rd(), registerSize
);
684 appendFPRegisterName(rn(), registerSize
);
686 appendFPRegisterName(rm(), registerSize
);
688 return m_formatBuffer
;
691 const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames
[4] = {
692 "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
695 const char* A64DOpcodeFloatingFixedPointConversions::format()
698 return A64DOpcode::format();
701 return A64DOpcode::format();
704 return A64DOpcode::format();
706 if (!(rmode() & 0x1) && !(opcode() & 0x6))
707 return A64DOpcode::format();
709 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
710 return A64DOpcode::format();
712 if (!(rmode() & 0x2) && !(opcode() & 0x6))
713 return A64DOpcode::format();
715 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
716 return A64DOpcode::format();
718 if (!is64Bit() && scale() >= 32)
719 return A64DOpcode::format();
721 appendInstructionName(opName());
722 unsigned FPRegisterSize
= type() + 2;
723 bool destIsFP
= !rmode();
726 appendFPRegisterName(rd(), FPRegisterSize
);
728 appendRegisterName(rn(), is64Bit());
730 appendRegisterName(rd(), is64Bit());
732 appendFPRegisterName(rn(), FPRegisterSize
);
735 appendUnsignedImmediate(64 - scale());
737 return m_formatBuffer
;
740 const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames
[32] = {
741 "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov",
742 "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov",
743 "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0,
744 "fcvtzs", "fcvtzu", 0, 0, 0, 0, 0, 0
747 const char* A64DOpcodeFloatingPointIntegerConversions::format()
750 return A64DOpcode::format();
753 return A64DOpcode::format();
755 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4)))
756 return A64DOpcode::format();
758 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
759 return A64DOpcode::format();
761 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
762 return A64DOpcode::format();
764 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
765 return A64DOpcode::format();
768 return A64DOpcode::format();
770 if ((opNum() & 0x1e) == 0xe) {
771 // Handle fmov to/from upper half of quad separately
772 if (!is64Bit() || (type() != 0x2))
773 return A64DOpcode::format();
775 appendInstructionName(opName());
776 if (opcode() & 0x1) {
778 bufferPrintf("V%u.D[1]", rd());
780 appendRegisterName(rn());
783 appendRegisterName(rd());
785 bufferPrintf("V%u.D[1]", rn());
788 return m_formatBuffer
;
791 appendInstructionName(opName());
792 unsigned FPRegisterSize
= type() + 2;
793 bool destIsFP
= ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
796 appendFPRegisterName(rd(), FPRegisterSize
);
798 appendRegisterName(rn(), is64Bit());
800 appendRegisterName(rd(), is64Bit());
802 appendFPRegisterName(rn(), FPRegisterSize
);
805 return m_formatBuffer
;
808 const char* const A64DOpcodeHint::s_opNames
[6] = {
809 "nop", "yield", "wfe", "wfi", "sev", "sevl"
812 const char* A64DOpcodeHint::format()
814 appendInstructionName(opName());
816 if (immediate7() > 5)
817 appendUnsignedImmediate(immediate7());
819 return m_formatBuffer
;
822 // A zero in an entry of the table means the instruction is Unallocated
823 const char* const A64DOpcodeLoadStore::s_opNames
[32] = {
824 "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
825 "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0,
826 "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0,
827 "str", "ldr", 0, 0, "str", "ldr", 0, 0
830 // A zero in an entry of the table means the instruction is Unallocated
831 const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames
[32] = {
832 "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0,
833 "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0,
834 "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0,
835 "sttr", "ldtr", 0, 0, 0, 0, 0, 0
838 // A zero in an entry of the table means the instruction is Unallocated
839 const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames
[32] = {
840 "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur",
841 "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0,
842 "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0,
843 "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0
846 const char* A64DOpcodeLoadStoreImmediate::format()
848 const char* thisOpName
;
851 thisOpName
= opName();
853 thisOpName
= unscaledOpName();
855 thisOpName
= unprivilegedOpName();
858 return A64DOpcode::format();
860 appendInstructionName(thisOpName
);
862 appendFPRegisterName(rt(), size());
864 appendRegisterName(rt(), is64BitRT());
866 appendCharacter('[');
867 appendSPOrRegisterName(rn());
870 case 0: // Unscaled Immediate
873 appendSignedImmediate(immediate9());
875 appendCharacter(']');
877 case 1: // Immediate Post-Indexed
878 appendCharacter(']');
881 appendSignedImmediate(immediate9());
884 case 2: // Unprivileged
887 appendSignedImmediate(immediate9());
889 appendCharacter(']');
891 case 3: // Immediate Pre-Indexed
894 appendSignedImmediate(immediate9());
896 appendCharacter(']');
897 appendCharacter('!');
901 return m_formatBuffer
;
904 const char* A64DOpcodeLoadStoreRegisterOffset::format()
906 const char* thisOpName
= opName();
909 return A64DOpcode::format();
911 if (!(option() & 0x2))
912 return A64DOpcode::format();
914 appendInstructionName(thisOpName
);
917 appendFPRegisterName(rt(), size());
918 scale
= ((opc() & 2)<<1) | size();
920 appendRegisterName(rt(), is64BitRT());
924 appendCharacter('[');
925 appendSPOrRegisterName(rn());
927 appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
929 unsigned shift
= sBit() ? scale
: 0;
931 if (option() == 0x3) {
934 appendString("lsl ");
935 appendUnsignedImmediate(shift
);
939 appendString(optionName());
941 appendUnsignedImmediate(shift
);
944 appendCharacter(']');
946 return m_formatBuffer
;
949 const char* A64DOpcodeLoadStoreRegisterPair::opName()
951 if (!vBit() && lBit() && size() == 0x1)
958 const char* A64DOpcodeLoadStoreRegisterPair::format()
960 const char* thisOpName
= opName();
963 return A64DOpcode::format();
965 if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
966 return A64DOpcode::format();
968 if ((offsetMode() == 0x1) && !vBit() && !lBit())
969 return A64DOpcode::format();
971 appendInstructionName(thisOpName
);
972 unsigned offsetShift
;
974 appendFPRegisterName(rt(), size());
976 appendFPRegisterName(rt2(), size());
977 offsetShift
= size() + 2;
979 appendRegisterName(rt(), is64Bit());
981 appendRegisterName(rt2(), is64Bit());
982 offsetShift
= (size() >> 1) + 2;
986 appendCharacter('[');
987 appendSPOrRegisterName(rn());
989 int offset
= immediate7() << offsetShift
;
991 if (offsetMode() == 1) {
992 appendCharacter(']');
994 appendSignedImmediate(offset
);
997 appendSignedImmediate(offset
);
998 appendCharacter(']');
999 if (offsetMode() == 0x3)
1000 appendCharacter('!');
1003 return m_formatBuffer
;
1006 const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
1008 const char* thisOpName
= opName();
1011 return A64DOpcode::format();
1013 appendInstructionName(thisOpName
);
1016 appendFPRegisterName(rt(), size());
1017 scale
= ((opc() & 2)<<1) | size();
1019 appendRegisterName(rt(), is64BitRT());
1023 appendCharacter('[');
1024 appendSPOrRegisterName(rn());
1026 if (immediate12()) {
1028 appendUnsignedImmediate(immediate12() << scale
);
1031 appendCharacter(']');
1033 return m_formatBuffer
;
1036 // A zero in an entry of the table means the instruction is Unallocated
1037 const char* const A64DOpcodeLogical::s_opNames
[8] = {
1038 "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics"
1041 const char* A64DOpcodeLogicalShiftedRegister::format()
1043 if (!is64Bit() && immediate6() & 0x20)
1044 return A64DOpcode::format();
1047 appendInstructionName("tst");
1050 appendInstructionName("mov");
1052 appendInstructionName(opName(opNumber()));
1053 appendSPOrRegisterName(rd(), is64Bit());
1058 appendRegisterName(rn(), is64Bit());
1062 appendZROrRegisterName(rm(), is64Bit());
1065 appendShiftType(shift());
1066 appendUnsignedImmediate(immediate6());
1069 return m_formatBuffer
;
1072 static unsigned highestBitSet(unsigned value
)
1074 unsigned result
= 0;
1082 static uint64_t rotateRight(uint64_t value
, unsigned width
, unsigned shift
)
1084 uint64_t result
= value
;
1087 result
= (value
>> (shift
% width
)) | (value
<< (width
- shift
));
1092 static uint64_t replicate(uint64_t value
, unsigned width
)
1094 uint64_t result
= 0;
1096 for (unsigned totalBits
= 0; totalBits
< 64; totalBits
+= width
)
1097 result
= (result
<< width
) | value
;
1102 const char* A64DOpcodeLogicalImmediate::format()
1104 if (!is64Bit() && nBit())
1105 return A64DOpcode::format();
1107 unsigned len
= highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
1108 unsigned levels
= (1 << len
) - 1; // len number of 1 bits starting at LSB
1110 if ((immediateS() & levels
) == levels
)
1111 return A64DOpcode::format();
1113 unsigned r
= immediateR() & levels
;
1114 unsigned s
= immediateS() & levels
;
1115 unsigned eSize
= 1 << len
;
1116 uint64_t pattern
= rotateRight((1ull << (s
+ 1)) - 1, eSize
, r
);
1118 uint64_t immediate
= replicate(pattern
, eSize
);
1121 immediate
&= 0xffffffffull
;
1124 appendInstructionName("tst");
1127 appendInstructionName("mov");
1129 appendInstructionName(opName(opNumber()));
1130 appendRegisterName(rd(), is64Bit());
1134 appendRegisterName(rn(), is64Bit());
1137 appendUnsignedImmediate64(immediate
);
1139 return m_formatBuffer
;
1142 const char* const A64DOpcodeMoveWide::s_opNames
[4] = { "movn", "", "movz", "movk" };
1144 const char* A64DOpcodeMoveWide::format()
1147 return A64DOpcode::format();
1148 if (!size() && hw() >= 2)
1149 return A64DOpcode::format();
1151 appendInstructionName(opName());
1152 appendRegisterName(rd(), is64Bit());
1154 appendUnsignedImmediate(immediate16());
1157 appendShiftAmount(hw());
1160 return m_formatBuffer
;
1163 const char* A64DOpcodeTestAndBranchImmediate::format()
1165 appendInstructionName(opBit() ? "tbnz" : "tbz");
1166 appendRegisterName(rt());
1168 appendUnsignedImmediate(bitNumber());
1170 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate14()));
1171 return m_formatBuffer
;
1174 const char* A64DOpcodeUnconditionalBranchImmediate::format()
1176 appendInstructionName(op() ? "bl" : "b");
1177 appendPCRelativeOffset(m_currentPC
, static_cast<int32_t>(immediate26()));
1178 return m_formatBuffer
;
1181 const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames
[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
1183 const char* A64DOpcodeUnconditionalBranchRegister::format()
1185 unsigned opcValue
= opc();
1186 if (opcValue
== 3 || opcValue
> 5)
1187 return A64DOpcode::format();
1188 if (((opcValue
& 0xe) == 0x4) && rn() != 0x1f)
1189 return A64DOpcode::format();
1190 appendInstructionName(opName());
1192 appendRegisterName(rn());
1193 return m_formatBuffer
;
1196 } } // namespace JSC::ARM64Disassembler