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