]> git.saurik.com Git - apple/javascriptcore.git/blob - disassembler/ARM64/A64DOpcode.cpp
415dbdb8e02ded4e318c82715df6542f5b1342ac
[apple/javascriptcore.git] / disassembler / ARM64 / A64DOpcode.cpp
1 /*
2 * Copyright (C) 2012 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 #include "A64DOpcode.h"
28
29 #include <stdarg.h>
30 #include <stdint.h>
31 #include <stdio.h>
32
33 namespace JSC { namespace ARM64Disassembler {
34
35 A64DOpcode::OpcodeGroup* A64DOpcode::opcodeTable[32];
36
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"
40 };
41
42 const char* const A64DOpcode::s_optionName[8] = {
43 "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"
44 };
45
46 const char* const A64DOpcode::s_shiftNames[4] = {
47 "lsl", "lsr", "asl", "ror"
48 };
49
50 const char A64DOpcode::s_FPRegisterPrefix[5] = {
51 'b', 'h', 's', 'd', 'q'
52 };
53
54 struct OpcodeGroupInitializer {
55 unsigned m_opcodeGroupNumber;
56 uint32_t m_mask;
57 uint32_t m_pattern;
58 const char* (*m_format)(A64DOpcode*);
59 };
60
61 #define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
62 { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
63
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),
103 };
104
105 bool A64DOpcode::s_initialized = false;
106
107 void A64DOpcode::init()
108 {
109 if (s_initialized)
110 return;
111
112 OpcodeGroup* lastGroups[32];
113
114 for (unsigned i = 0; i < 32; i++) {
115 opcodeTable[i] = 0;
116 lastGroups[i] = 0;
117 }
118
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;
122
123 if (!opcodeTable[opcodeGroupNumber])
124 opcodeTable[opcodeGroupNumber] = newOpcodeGroup;
125 else
126 lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup);
127 lastGroups[opcodeGroupNumber] = newOpcodeGroup;
128 }
129
130 s_initialized = true;
131 }
132
133 void A64DOpcode::setPCAndOpcode(uint32_t* newPC, uint32_t newOpcode)
134 {
135 m_currentPC = newPC;
136 m_opcode = newOpcode;
137 m_bufferOffset = 0;
138 m_formatBuffer[0] = '\0';
139 }
140
141 const char* A64DOpcode::disassemble(uint32_t* currentPC)
142 {
143 setPCAndOpcode(currentPC, *currentPC);
144
145 OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)];
146
147 while (opGroup) {
148 if (opGroup->matches(m_opcode))
149 return opGroup->format(this);
150 opGroup = opGroup->next();
151 }
152
153 return A64DOpcode::format();
154 }
155
156 void A64DOpcode::bufferPrintf(const char* format, ...)
157 {
158 if (m_bufferOffset >= bufferSize)
159 return;
160
161 va_list argList;
162 va_start(argList, format);
163
164 m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList);
165
166 va_end(argList);
167 }
168
169 const char* A64DOpcode::format()
170 {
171 bufferPrintf(" .long %08x", m_opcode);
172 return m_formatBuffer;
173 }
174
175 void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit)
176 {
177 if (registerNumber == 29) {
178 bufferPrintf(is64Bit ? "fp" : "wfp");
179 return;
180 }
181
182 if (registerNumber == 30) {
183 bufferPrintf(is64Bit ? "lr" : "wlr");
184 return;
185 }
186
187 bufferPrintf("%c%u", is64Bit ? 'x' : 'w', registerNumber);
188 }
189
190 void A64DOpcode::appendFPRegisterName(unsigned registerNumber, unsigned registerSize)
191 {
192 bufferPrintf("%c%u", FPRegisterPrefix(registerSize), registerNumber);
193 }
194
195 const char* const A64DOpcodeAddSubtract::s_opNames[4] = { "add", "adds", "sub", "subs" };
196
197 const char* A64DOpcodeAddSubtractImmediate::format()
198 {
199 if (isCMP())
200 appendInstructionName(cmpName());
201 else {
202 if (isMovSP())
203 appendInstructionName("mov");
204 else
205 appendInstructionName(opName());
206 appendSPOrRegisterName(rd(), is64Bit());
207 appendSeparator();
208 }
209 appendSPOrRegisterName(rn(), is64Bit());
210
211 if (!isMovSP()) {
212 appendSeparator();
213 appendUnsignedImmediate(immed12());
214 if (shift()) {
215 appendSeparator();
216 appendString(shift() == 1 ? "lsl" : "reserved");
217 }
218 }
219 return m_formatBuffer;
220 }
221
222 const char* A64DOpcodeAddSubtractExtendedRegister::format()
223 {
224 if (immediate3() > 4)
225 return A64DOpcode::format();
226
227 if (isCMP())
228 appendInstructionName(cmpName());
229 else {
230 appendInstructionName(opName());
231 appendSPOrRegisterName(rd(), is64Bit());
232 appendSeparator();
233 }
234 appendSPOrRegisterName(rn(), is64Bit());
235 appendSeparator();
236 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
237 appendSeparator();
238 if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
239 appendString("lsl");
240 else
241 appendString(optionName());
242 if (immediate3()) {
243 appendCharacter(' ');
244 appendUnsignedImmediate(immediate3());
245 }
246
247 return m_formatBuffer;
248 }
249
250 const char* A64DOpcodeAddSubtractShiftedRegister::format()
251 {
252 if (!is64Bit() && immediate6() & 0x20)
253 return A64DOpcode::format();
254
255 if (shift() == 0x3)
256 return A64DOpcode::format();
257
258 if (isCMP())
259 appendInstructionName(cmpName());
260 else {
261 if (isNeg())
262 appendInstructionName(cmpName());
263 else
264 appendInstructionName(opName());
265 appendSPOrRegisterName(rd(), is64Bit());
266 appendSeparator();
267 }
268 if (!isNeg()) {
269 appendRegisterName(rn(), is64Bit());
270 appendSeparator();
271 }
272 appendZROrRegisterName(rm(), is64Bit());
273 if (immediate6()) {
274 appendSeparator();
275 appendShiftType(shift());
276 appendUnsignedImmediate(immediate6());
277 }
278
279 return m_formatBuffer;
280 }
281
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" };
287
288 const char* A64DOpcodeBitfield::format()
289 {
290 if (opc() == 0x3)
291 return A64DOpcode::format();
292
293 if (is64Bit() != nBit())
294 return A64DOpcode::format();
295
296 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
297 return A64DOpcode::format();
298
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));
304 isSTXType = true;
305 } else if (immediateS() == 15) {
306 appendInstructionName(extendPseudoOpNames(1));
307 isSTXType = true;
308 } else if (immediateS() == 31 && is64Bit()) {
309 appendInstructionName(extendPseudoOpNames(2));
310 isSTXType = true;
311 }
312
313 if (isSTXType) {
314 appendRegisterName(rd(), is64Bit());
315 appendSeparator();
316 appendRegisterName(rn(), false);
317
318 return m_formatBuffer;
319 }
320 }
321
322 if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
323 // lsl
324 appendInstructionName("lsl");
325 appendRegisterName(rd(), is64Bit());
326 appendSeparator();
327 appendRegisterName(rn(), is64Bit());
328 appendSeparator();
329 appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
330
331 return m_formatBuffer;
332 } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
333 // asr/lsr
334 appendInstructionName(!opc() ? "ars" : "lsr");
335
336 appendRegisterName(rd(), is64Bit());
337 appendSeparator();
338 appendRegisterName(rn(), is64Bit());
339 appendSeparator();
340 appendUnsignedImmediate(immediateR());
341
342 return m_formatBuffer;
343 } else if (immediateS() < immediateR()) {
344 // bit field insert
345 appendInstructionName(insertOpNames());
346
347 appendRegisterName(rd(), is64Bit());
348 appendSeparator();
349 appendRegisterName(rn(), is64Bit());
350 appendSeparator();
351 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
352 appendSeparator();
353 appendUnsignedImmediate(immediateS() + 1);
354
355 return m_formatBuffer;
356 } else {
357 // bit field extract
358 appendInstructionName(extractOpNames());
359
360 appendRegisterName(rd(), is64Bit());
361 appendSeparator();
362 appendRegisterName(rn(), is64Bit());
363 appendSeparator();
364 appendUnsignedImmediate(immediateR());
365 appendSeparator();
366 appendUnsignedImmediate(immediateS() - immediateR() + 1);
367
368 return m_formatBuffer;
369 }
370
371 appendInstructionName(opName());
372 appendRegisterName(rd(), is64Bit());
373 appendSeparator();
374 appendRegisterName(rn(), is64Bit());
375 appendSeparator();
376 appendUnsignedImmediate(immediateR());
377 appendSeparator();
378 appendUnsignedImmediate(immediateS());
379
380 return m_formatBuffer;
381 }
382
383 const char* A64DOpcodeCompareAndBranchImmediate::format()
384 {
385 appendInstructionName(opBit() ? "cbnz" : "cbz");
386 appendRegisterName(rt(), is64Bit());
387 appendSeparator();
388 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
389 return m_formatBuffer;
390 }
391
392 const char* A64DOpcodeConditionalBranchImmediate::format()
393 {
394 bufferPrintf(" b.%-5.5s", conditionName(condition()));
395 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
396 return m_formatBuffer;
397 }
398
399 const char* const A64DOpcodeConditionalSelect::s_opNames[4] = {
400 "csel", "csinc", "csinv", "csneg"
401 };
402
403 const char* A64DOpcodeConditionalSelect::format()
404 {
405 if (sBit())
406 return A64DOpcode::format();
407
408 if (op2() & 0x2)
409 return A64DOpcode::format();
410
411 if (rn() == rm() && (opNum() == 1 || opNum() == 2)) {
412 if (rn() == 31) {
413 appendInstructionName((opNum() == 1) ? "cset" : "csetm");
414 appendRegisterName(rd(), is64Bit());
415 } else {
416 appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
417 appendRegisterName(rd(), is64Bit());
418 appendSeparator();
419 appendZROrRegisterName(rn(), is64Bit());
420 }
421 appendSeparator();
422 appendString(conditionName(condition() ^ 0x1));
423
424 return m_formatBuffer;
425 }
426
427 appendInstructionName(opName());
428 appendRegisterName(rd(), is64Bit());
429 appendSeparator();
430 appendZROrRegisterName(rn(), is64Bit());
431 appendSeparator();
432 appendZROrRegisterName(rm(), is64Bit());
433 appendSeparator();
434 appendString(conditionName(condition()));
435
436 return m_formatBuffer;
437
438 }
439
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
442 };
443
444 const char* A64DOpcodeDataProcessing2Source::format()
445 {
446 if (sBit())
447 return A64DOpcode::format();
448
449 if (!(opCode() & 0x3e))
450 return A64DOpcode::format();
451
452 if (opCode() & 0x30)
453 return A64DOpcode::format();
454
455 if ((opCode() & 0x34) == 0x4)
456 return A64DOpcode::format();
457
458 appendInstructionName(opName());
459 appendRegisterName(rd(), is64Bit());
460 appendSeparator();
461 appendRegisterName(rn(), is64Bit());
462 appendSeparator();
463 appendRegisterName(rm(), is64Bit());
464
465 return m_formatBuffer;
466 }
467
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
471 };
472
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
476 };
477
478 const char* A64DOpcodeDataProcessing3Source::format()
479 {
480 if (op54())
481 return A64DOpcode::format();
482
483 if (opNum() > 12)
484 return A64DOpcode::format();
485
486 if (!is64Bit() && opNum() > 1)
487 return A64DOpcode::format();
488
489 if (!opName())
490 return A64DOpcode::format();
491
492 appendInstructionName(opName());
493 appendRegisterName(rd(), is64Bit());
494 appendSeparator();
495 bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2);
496 appendRegisterName(rn(), srcOneAndTwoAre64Bit);
497 appendSeparator();
498 appendRegisterName(rm(), srcOneAndTwoAre64Bit);
499
500 if ((ra() != 31) || !(opNum() & 0x4)) {
501 appendSeparator();
502 appendRegisterName(ra(), is64Bit());
503 }
504
505 return m_formatBuffer;
506 }
507
508 const char* A64OpcodeExceptionGeneration::format()
509 {
510 const char* opname = 0;
511 if (!op2()) {
512 switch (opc()) {
513 case 0x0: // SVC, HVC & SMC
514 switch (ll()) {
515 case 0x1:
516 opname = "svc";
517 break;
518 case 0x2:
519 opname = "hvc";
520 break;
521 case 0x3:
522 opname = "smc";
523 break;
524 }
525 break;
526 case 0x1: // BRK
527 if (!ll())
528 opname = "brk";
529 break;
530 case 0x2: // HLT
531 if (!ll())
532 opname = "hlt";
533 break;
534 case 0x5: // DPCS1-3
535 switch (ll()) {
536 case 0x1:
537 opname = "dpcs1";
538 break;
539 case 0x2:
540 opname = "dpcs2";
541 break;
542 case 0x3:
543 opname = "dpcs3";
544 break;
545 }
546 break;
547 }
548 }
549
550 if (!opname)
551 return A64DOpcode::format();
552
553 appendInstructionName(opname);
554 appendUnsignedImmediate(immediate16());
555 return m_formatBuffer;
556 }
557
558 const char* A64DOpcodeExtract::format()
559 {
560 if (!op21() || !o0Bit())
561 return A64DOpcode::format();
562
563 if (is64Bit() != nBit())
564 return A64DOpcode::format();
565
566 if (is64Bit() && (immediateS() & 0x20))
567 return A64DOpcode::format();
568
569 const char* opName = (rn() == rm()) ? "ror" : "extr";
570
571 appendInstructionName(opName);
572 appendRegisterName(rd(), is64Bit());
573 appendSeparator();
574 appendRegisterName(rn(), is64Bit());
575 appendSeparator();
576 appendRegisterName(rm(), is64Bit());
577 appendSeparator();
578 appendUnsignedImmediate(immediateS());
579
580 return m_formatBuffer;
581 }
582
583 const char* A64DOpcodeFloatingPointCompare::format()
584 {
585 if (mBit())
586 return A64DOpcode::format();
587
588 if (sBit())
589 return A64DOpcode::format();
590
591 if (type() & 0x2)
592 return A64DOpcode::format();
593
594 if (op())
595 return A64DOpcode::format();
596
597 if (opCode2() & 0x7)
598 return A64DOpcode::format();
599
600 appendInstructionName(opName());
601 unsigned registerSize = type() + 2;
602 appendFPRegisterName(rn(), registerSize);
603 appendSeparator();
604 if (opCode2() & 0x8)
605 bufferPrintf("#0.0");
606 else
607 appendFPRegisterName(rm(), registerSize);
608
609 return m_formatBuffer;
610 }
611
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"
615 };
616
617 const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
618 {
619 if (mBit())
620 return A64DOpcode::format();
621
622 if (sBit())
623 return A64DOpcode::format();
624
625 if (opNum() > 16)
626 return A64DOpcode::format();
627
628 switch (type()) {
629 case 0:
630 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
631 return A64DOpcode::format();
632 break;
633 case 1:
634 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
635 return A64DOpcode::format();
636 break;
637 case 2:
638 return A64DOpcode::format();
639 case 3:
640 if ((opNum() < 0x4) || (opNum() > 0x5))
641 return A64DOpcode::format();
642 break;
643 }
644
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);
650 appendSeparator();
651 appendFPRegisterName(rn(), srcRegisterSize);
652 } else {
653 unsigned registerSize = type() + 2;
654 appendFPRegisterName(rd(), registerSize);
655 appendSeparator();
656 appendFPRegisterName(rn(), registerSize);
657 }
658
659 return m_formatBuffer;
660 }
661
662 const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames[16] = {
663 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
664 };
665
666 const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
667 {
668 if (mBit())
669 return A64DOpcode::format();
670
671 if (sBit())
672 return A64DOpcode::format();
673
674 if (type() & 0x2)
675 return A64DOpcode::format();
676
677 if (opNum() > 8)
678 return A64DOpcode::format();
679
680 appendInstructionName(opName());
681 unsigned registerSize = type() + 2;
682 appendFPRegisterName(rd(), registerSize);
683 appendSeparator();
684 appendFPRegisterName(rn(), registerSize);
685 appendSeparator();
686 appendFPRegisterName(rm(), registerSize);
687
688 return m_formatBuffer;
689 }
690
691 const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames[4] = {
692 "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
693 };
694
695 const char* A64DOpcodeFloatingFixedPointConversions::format()
696 {
697 if (sBit())
698 return A64DOpcode::format();
699
700 if (type() & 0x2)
701 return A64DOpcode::format();
702
703 if (opcode() & 0x4)
704 return A64DOpcode::format();
705
706 if (!(rmode() & 0x1) && !(opcode() & 0x6))
707 return A64DOpcode::format();
708
709 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
710 return A64DOpcode::format();
711
712 if (!(rmode() & 0x2) && !(opcode() & 0x6))
713 return A64DOpcode::format();
714
715 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
716 return A64DOpcode::format();
717
718 if (!is64Bit() && scale() >= 32)
719 return A64DOpcode::format();
720
721 appendInstructionName(opName());
722 unsigned FPRegisterSize = type() + 2;
723 bool destIsFP = !rmode();
724
725 if (destIsFP) {
726 appendFPRegisterName(rd(), FPRegisterSize);
727 appendSeparator();
728 appendRegisterName(rn(), is64Bit());
729 } else {
730 appendRegisterName(rd(), is64Bit());
731 appendSeparator();
732 appendFPRegisterName(rn(), FPRegisterSize);
733 }
734 appendSeparator();
735 appendUnsignedImmediate(64 - scale());
736
737 return m_formatBuffer;
738 }
739
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
745 };
746
747 const char* A64DOpcodeFloatingPointIntegerConversions::format()
748 {
749 if (sBit())
750 return A64DOpcode::format();
751
752 if (type() == 0x3)
753 return A64DOpcode::format();
754
755 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4)))
756 return A64DOpcode::format();
757
758 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
759 return A64DOpcode::format();
760
761 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
762 return A64DOpcode::format();
763
764 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
765 return A64DOpcode::format();
766
767 if (!opName())
768 return A64DOpcode::format();
769
770 if ((opNum() & 0x1e) == 0xe) {
771 // Handle fmov to/from upper half of quad separately
772 if (!is64Bit() || (type() != 0x2))
773 return A64DOpcode::format();
774
775 appendInstructionName(opName());
776 if (opcode() & 0x1) {
777 // fmov Vd.D[1], Xn
778 bufferPrintf("V%u.D[1]", rd());
779 appendSeparator();
780 appendRegisterName(rn());
781 } else {
782 // fmov Xd, Vn.D[1]
783 appendRegisterName(rd());
784 appendSeparator();
785 bufferPrintf("V%u.D[1]", rn());
786 }
787
788 return m_formatBuffer;
789 }
790
791 appendInstructionName(opName());
792 unsigned FPRegisterSize = type() + 2;
793 bool destIsFP = ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
794
795 if (destIsFP) {
796 appendFPRegisterName(rd(), FPRegisterSize);
797 appendSeparator();
798 appendRegisterName(rn(), is64Bit());
799 } else {
800 appendRegisterName(rd(), is64Bit());
801 appendSeparator();
802 appendFPRegisterName(rn(), FPRegisterSize);
803 }
804
805 return m_formatBuffer;
806 }
807
808 const char* const A64DOpcodeHint::s_opNames[6] = {
809 "nop", "yield", "wfe", "wfi", "sev", "sevl"
810 };
811
812 const char* A64DOpcodeHint::format()
813 {
814 appendInstructionName(opName());
815
816 if (immediate7() > 5)
817 appendUnsignedImmediate(immediate7());
818
819 return m_formatBuffer;
820 }
821
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
828 };
829
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
836 };
837
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
844 };
845
846 const char* A64DOpcodeLoadStoreImmediate::format()
847 {
848 const char* thisOpName;
849
850 if (type() & 0x1)
851 thisOpName = opName();
852 else if (!type())
853 thisOpName = unscaledOpName();
854 else
855 thisOpName = unprivilegedOpName();
856
857 if (!thisOpName)
858 return A64DOpcode::format();
859
860 appendInstructionName(thisOpName);
861 if (vBit())
862 appendFPRegisterName(rt(), size());
863 else
864 appendRegisterName(rt(), is64BitRT());
865 appendSeparator();
866 appendCharacter('[');
867 appendSPOrRegisterName(rn());
868
869 switch (type()) {
870 case 0: // Unscaled Immediate
871 if (immediate9()) {
872 appendSeparator();
873 appendSignedImmediate(immediate9());
874 }
875 appendCharacter(']');
876 break;
877 case 1: // Immediate Post-Indexed
878 appendCharacter(']');
879 if (immediate9()) {
880 appendSeparator();
881 appendSignedImmediate(immediate9());
882 }
883 break;
884 case 2: // Unprivileged
885 if (immediate9()) {
886 appendSeparator();
887 appendSignedImmediate(immediate9());
888 }
889 appendCharacter(']');
890 break;
891 case 3: // Immediate Pre-Indexed
892 if (immediate9()) {
893 appendSeparator();
894 appendSignedImmediate(immediate9());
895 }
896 appendCharacter(']');
897 appendCharacter('!');
898 break;
899 }
900
901 return m_formatBuffer;
902 }
903
904 const char* A64DOpcodeLoadStoreRegisterOffset::format()
905 {
906 const char* thisOpName = opName();
907
908 if (!thisOpName)
909 return A64DOpcode::format();
910
911 if (!(option() & 0x2))
912 return A64DOpcode::format();
913
914 appendInstructionName(thisOpName);
915 unsigned scale;
916 if (vBit()) {
917 appendFPRegisterName(rt(), size());
918 scale = ((opc() & 2)<<1) | size();
919 } else {
920 appendRegisterName(rt(), is64BitRT());
921 scale = size();
922 }
923 appendSeparator();
924 appendCharacter('[');
925 appendSPOrRegisterName(rn());
926 appendSeparator();
927 appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
928
929 unsigned shift = sBit() ? scale : 0;
930
931 if (option() == 0x3) {
932 if (shift) {
933 appendSeparator();
934 appendString("lsl ");
935 appendUnsignedImmediate(shift);
936 }
937 } else {
938 appendSeparator();
939 appendString(optionName());
940 if (shift)
941 appendUnsignedImmediate(shift);
942 }
943
944 appendCharacter(']');
945
946 return m_formatBuffer;
947 }
948
949 const char* A64DOpcodeLoadStoreRegisterPair::opName()
950 {
951 if (!vBit() && lBit() && size() == 0x1)
952 return "ldpsw";
953 if (lBit())
954 return "ldp";
955 return "stp";
956 }
957
958 const char* A64DOpcodeLoadStoreRegisterPair::format()
959 {
960 const char* thisOpName = opName();
961
962 if (size() == 0x3)
963 return A64DOpcode::format();
964
965 if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
966 return A64DOpcode::format();
967
968 if ((offsetMode() == 0x1) && !vBit() && !lBit())
969 return A64DOpcode::format();
970
971 appendInstructionName(thisOpName);
972 unsigned offsetShift;
973 if (vBit()) {
974 appendFPRegisterName(rt(), size());
975 appendSeparator();
976 appendFPRegisterName(rt2(), size());
977 offsetShift = size() + 2;
978 } else {
979 appendRegisterName(rt(), is64Bit());
980 appendSeparator();
981 appendRegisterName(rt2(), is64Bit());
982 offsetShift = (size() >> 1) + 2;
983 }
984
985 appendSeparator();
986 appendCharacter('[');
987 appendSPOrRegisterName(rn());
988
989 int offset = immediate7() << offsetShift;
990
991 if (offsetMode() == 1) {
992 appendCharacter(']');
993 appendSeparator();
994 appendSignedImmediate(offset);
995 } else {
996 appendSeparator();
997 appendSignedImmediate(offset);
998 appendCharacter(']');
999 if (offsetMode() == 0x3)
1000 appendCharacter('!');
1001 }
1002
1003 return m_formatBuffer;
1004 }
1005
1006 const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
1007 {
1008 const char* thisOpName = opName();
1009
1010 if (!thisOpName)
1011 return A64DOpcode::format();
1012
1013 appendInstructionName(thisOpName);
1014 unsigned scale;
1015 if (vBit()) {
1016 appendFPRegisterName(rt(), size());
1017 scale = ((opc() & 2)<<1) | size();
1018 } else {
1019 appendRegisterName(rt(), is64BitRT());
1020 scale = size();
1021 }
1022 appendSeparator();
1023 appendCharacter('[');
1024 appendSPOrRegisterName(rn());
1025
1026 if (immediate12()) {
1027 appendSeparator();
1028 appendUnsignedImmediate(immediate12() << scale);
1029 }
1030
1031 appendCharacter(']');
1032
1033 return m_formatBuffer;
1034 }
1035
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"
1039 };
1040
1041 const char* A64DOpcodeLogicalShiftedRegister::format()
1042 {
1043 if (!is64Bit() && immediate6() & 0x20)
1044 return A64DOpcode::format();
1045
1046 if (isTst())
1047 appendInstructionName("tst");
1048 else {
1049 if (isMov())
1050 appendInstructionName("mov");
1051 else
1052 appendInstructionName(opName(opNumber()));
1053 appendSPOrRegisterName(rd(), is64Bit());
1054 appendSeparator();
1055 }
1056
1057 if (!isMov()) {
1058 appendRegisterName(rn(), is64Bit());
1059 appendSeparator();
1060 }
1061
1062 appendZROrRegisterName(rm(), is64Bit());
1063 if (immediate6()) {
1064 appendSeparator();
1065 appendShiftType(shift());
1066 appendUnsignedImmediate(immediate6());
1067 }
1068
1069 return m_formatBuffer;
1070 }
1071
1072 static unsigned highestBitSet(unsigned value)
1073 {
1074 unsigned result = 0;
1075
1076 while (value >>= 1)
1077 result++;
1078
1079 return result;
1080 }
1081
1082 static uint64_t rotateRight(uint64_t value, unsigned width, unsigned shift)
1083 {
1084 uint64_t result = value;
1085
1086 if (shift)
1087 result = (value >> (shift % width)) | (value << (width - shift));
1088
1089 return result;
1090 }
1091
1092 static uint64_t replicate(uint64_t value, unsigned width)
1093 {
1094 uint64_t result = 0;
1095
1096 for (unsigned totalBits = 0; totalBits < 64; totalBits += width)
1097 result = (result << width) | value;
1098
1099 return result;
1100 }
1101
1102 const char* A64DOpcodeLogicalImmediate::format()
1103 {
1104 if (!is64Bit() && nBit())
1105 return A64DOpcode::format();
1106
1107 unsigned len = highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
1108 unsigned levels = (1 << len) - 1; // len number of 1 bits starting at LSB
1109
1110 if ((immediateS() & levels) == levels)
1111 return A64DOpcode::format();
1112
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);
1117
1118 uint64_t immediate = replicate(pattern, eSize);
1119
1120 if (!is64Bit())
1121 immediate &= 0xffffffffull;
1122
1123 if (isTst())
1124 appendInstructionName("tst");
1125 else {
1126 if (isMov())
1127 appendInstructionName("mov");
1128 else
1129 appendInstructionName(opName(opNumber()));
1130 appendRegisterName(rd(), is64Bit());
1131 appendSeparator();
1132 }
1133 if (!isMov()) {
1134 appendRegisterName(rn(), is64Bit());
1135 appendSeparator();
1136 }
1137 appendUnsignedImmediate64(immediate);
1138
1139 return m_formatBuffer;
1140 }
1141
1142 const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", "", "movz", "movk" };
1143
1144 const char* A64DOpcodeMoveWide::format()
1145 {
1146 if (opc() == 1)
1147 return A64DOpcode::format();
1148 if (!size() && hw() >= 2)
1149 return A64DOpcode::format();
1150
1151 appendInstructionName(opName());
1152 appendRegisterName(rd(), is64Bit());
1153 appendSeparator();
1154 appendUnsignedImmediate(immediate16());
1155 if (hw()) {
1156 appendSeparator();
1157 appendShiftAmount(hw());
1158 }
1159
1160 return m_formatBuffer;
1161 }
1162
1163 const char* A64DOpcodeTestAndBranchImmediate::format()
1164 {
1165 appendInstructionName(opBit() ? "tbnz" : "tbz");
1166 appendRegisterName(rt());
1167 appendSeparator();
1168 appendUnsignedImmediate(bitNumber());
1169 appendSeparator();
1170 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate14()));
1171 return m_formatBuffer;
1172 }
1173
1174 const char* A64DOpcodeUnconditionalBranchImmediate::format()
1175 {
1176 appendInstructionName(op() ? "bl" : "b");
1177 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate26()));
1178 return m_formatBuffer;
1179 }
1180
1181 const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
1182
1183 const char* A64DOpcodeUnconditionalBranchRegister::format()
1184 {
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());
1191 if (opcValue <= 2)
1192 appendRegisterName(rn());
1193 return m_formatBuffer;
1194 }
1195
1196 } } // namespace JSC::ARM64Disassembler