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