blob: 271a9b9b38f28a1a13b76a71b1425ff6e23d02d8 [file] [log] [blame]
bigbiff673c7ae2020-12-02 19:44:56 -05001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#define LOG_TAG "ArmToArm64Assembler"
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include <cutils/properties.h>
36#include <log/log.h>
37#include <private/pixelflinger/ggl_context.h>
38
39#include "codeflinger/Arm64Assembler.h"
40#include "codeflinger/Arm64Disassembler.h"
41#include "codeflinger/CodeCache.h"
42
43/*
44** --------------------------------------------
45** Support for Arm64 in GGLAssembler JIT
46** --------------------------------------------
47**
48** Approach
49** - GGLAssembler and associated files are largely un-changed.
50** - A translator class maps ArmAssemblerInterface calls to
51** generate Arm64 instructions.
52**
53** ----------------------
54** ArmToArm64Assembler
55** ----------------------
56**
57** - Subclassed from ArmAssemblerInterface
58**
59** - Translates each ArmAssemblerInterface call to generate
60** one or more Arm64 instructions as necessary.
61**
62** - Does not implement ArmAssemblerInterface portions unused by GGLAssembler
63** It calls NOT_IMPLEMENTED() for such cases, which in turn logs
64** a fatal message.
65**
66** - Uses A64_.. series of functions to generate instruction machine code
67** for Arm64 instructions. These functions also log the instruction
68** to LOG, if ARM64_ASM_DEBUG define is set to 1
69**
70** - Dumps machine code and eqvt assembly if "debug.pf.disasm" option is set
71** It uses arm64_disassemble to perform disassembly
72**
73** - Uses register 13 (SP in ARM), 15 (PC in ARM), 16, 17 for storing
74** intermediate results. GGLAssembler does not use SP and PC as these
75** registers are marked as reserved. The temporary registers are not
76** saved/restored on stack as these are caller-saved registers in Arm64
77**
78** - Uses CSEL instruction to support conditional execution. The result is
79** stored in a temporary register and then copied to the target register
80** if the condition is true.
81**
82** - In the case of conditional data transfer instructions, conditional
83** branch is used to skip over instruction, if the condition is false
84**
85** - Wherever possible, immediate values are transferred to temporary
86** register prior to processing. This simplifies overall implementation
87** as instructions requiring immediate values are converted to
88** move immediate instructions followed by register-register instruction.
89**
90** --------------------------------------------
91** ArmToArm64Assembler unit test bench
92** --------------------------------------------
93**
94** - Tests ArmToArm64Assembler interface for all the possible
95** ways in which GGLAssembler uses ArmAssemblerInterface interface.
96**
97** - Uses test jacket (written in assembly) to set the registers,
98** condition flags prior to calling generated instruction. It also
99** copies registers and flags at the end of execution. Caller then
100** checks if generated code performed correct operation based on
101** output registers and flags.
102**
103** - Broadly contains three type of tests, (i) data operation tests
104** (ii) data transfer tests and (iii) LDM/STM tests.
105**
106** ----------------------
107** Arm64 disassembler
108** ----------------------
109** - This disassembler disassembles only those machine codes which can be
110** generated by ArmToArm64Assembler. It has a unit testbench which
111** tests all the instructions supported by the disassembler.
112**
113** ------------------------------------------------------------------
114** ARMAssembler/ARMAssemblerInterface/ARMAssemblerProxy changes
115** ------------------------------------------------------------------
116**
117** - In existing code, addresses were being handled as 32 bit values at
118** certain places.
119**
120** - Added a new set of functions for address load/store/manipulation.
121** These are ADDR_LDR, ADDR_STR, ADDR_ADD, ADDR_SUB and they map to
122** default 32 bit implementations in ARMAssemblerInterface.
123**
124** - ArmToArm64Assembler maps these functions to appropriate 64 bit
125** functions.
126**
127** ----------------------
128** GGLAssembler changes
129** ----------------------
130** - Since ArmToArm64Assembler can generate 4 Arm64 instructions for
131** each call in worst case, the memory required is set to 4 times
132** ARM memory
133**
134** - Address load/store/manipulation were changed to use new functions
135** added in the ARMAssemblerInterface.
136**
137*/
138
139
140#define NOT_IMPLEMENTED() LOG_FATAL("Arm instruction %s not yet implemented\n", __func__)
141
142#define ARM64_ASM_DEBUG 0
143
144#if ARM64_ASM_DEBUG
145 #define LOG_INSTR(...) ALOGD("\t" __VA_ARGS__)
146 #define LOG_LABEL(...) ALOGD(__VA_ARGS__)
147#else
148 #define LOG_INSTR(...) ((void)0)
149 #define LOG_LABEL(...) ((void)0)
150#endif
151
152namespace android {
153
154static __unused const char* shift_codes[] =
155{
156 "LSL", "LSR", "ASR", "ROR"
157};
158static __unused const char *cc_codes[] =
159{
160 "EQ", "NE", "CS", "CC", "MI",
161 "PL", "VS", "VC", "HI", "LS",
162 "GE", "LT", "GT", "LE", "AL", "NV"
163};
164
165ArmToArm64Assembler::ArmToArm64Assembler(const sp<Assembly>& assembly)
166 : ARMAssemblerInterface(),
167 mAssembly(assembly)
168{
169 mBase = mPC = (uint32_t *)assembly->base();
170 mDuration = ggl_system_time();
171 mZeroReg = 13;
172 mTmpReg1 = 15;
173 mTmpReg2 = 16;
174 mTmpReg3 = 17;
175}
176
177ArmToArm64Assembler::ArmToArm64Assembler(void *base)
178 : ARMAssemblerInterface(), mAssembly(NULL)
179{
180 mBase = mPC = (uint32_t *)base;
181 mDuration = ggl_system_time();
182 // Regs 13, 15, 16, 17 are used as temporary registers
183 mZeroReg = 13;
184 mTmpReg1 = 15;
185 mTmpReg2 = 16;
186 mTmpReg3 = 17;
187}
188
189ArmToArm64Assembler::~ArmToArm64Assembler()
190{
191}
192
193uint32_t* ArmToArm64Assembler::pc() const
194{
195 return mPC;
196}
197
198uint32_t* ArmToArm64Assembler::base() const
199{
200 return mBase;
201}
202
203void ArmToArm64Assembler::reset()
204{
205 if(mAssembly == NULL)
206 mPC = mBase;
207 else
208 mBase = mPC = (uint32_t *)mAssembly->base();
209 mBranchTargets.clear();
210 mLabels.clear();
211 mLabelsInverseMapping.clear();
212 mComments.clear();
213#if ARM64_ASM_DEBUG
214 ALOGI("RESET\n");
215#endif
216}
217
218int ArmToArm64Assembler::getCodegenArch()
219{
220 return CODEGEN_ARCH_ARM64;
221}
222
223// ----------------------------------------------------------------------------
224
225void ArmToArm64Assembler::disassemble(const char* name)
226{
227 if(name)
228 {
229 printf("%s:\n", name);
230 }
231 size_t count = pc()-base();
232 uint32_t* i = base();
233 while (count--)
234 {
235 ssize_t label = mLabelsInverseMapping.indexOfKey(i);
236 if (label >= 0)
237 {
238 printf("%s:\n", mLabelsInverseMapping.valueAt(label));
239 }
240 ssize_t comment = mComments.indexOfKey(i);
241 if (comment >= 0)
242 {
243 printf("; %s\n", mComments.valueAt(comment));
244 }
245 printf("%p: %08x ", i, uint32_t(i[0]));
246 {
247 char instr[256];
248 ::arm64_disassemble(*i, instr);
249 printf("%s\n", instr);
250 }
251 i++;
252 }
253}
254
255void ArmToArm64Assembler::comment(const char* string)
256{
257 mComments.add(mPC, string);
258 LOG_INSTR("//%s\n", string);
259}
260
261void ArmToArm64Assembler::label(const char* theLabel)
262{
263 mLabels.add(theLabel, mPC);
264 mLabelsInverseMapping.add(mPC, theLabel);
265 LOG_LABEL("%s:\n", theLabel);
266}
267
268void ArmToArm64Assembler::B(int cc, const char* label)
269{
270 mBranchTargets.add(branch_target_t(label, mPC));
271 LOG_INSTR("B%s %s\n", cc_codes[cc], label );
272 *mPC++ = (0x54 << 24) | cc;
273}
274
275void ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
276{
277 NOT_IMPLEMENTED(); //Not Required
278}
279
280// ----------------------------------------------------------------------------
281//Prolog/Epilog & Generate...
282// ----------------------------------------------------------------------------
283
284void ArmToArm64Assembler::prolog()
285{
286 // write prolog code
287 mPrologPC = mPC;
288 *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
289}
290
291void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
292{
293 // write epilog code
294 static const int XLR = 30;
295 *mPC++ = A64_RET(XLR);
296}
297
298int ArmToArm64Assembler::generate(const char* name)
299{
300 // fixup all the branches
301 size_t count = mBranchTargets.size();
302 while (count--)
303 {
304 const branch_target_t& bt = mBranchTargets[count];
305 uint32_t* target_pc = mLabels.valueFor(bt.label);
306 LOG_ALWAYS_FATAL_IF(!target_pc,
307 "error resolving branch targets, target_pc is null");
308 int32_t offset = int32_t(target_pc - bt.pc);
309 *bt.pc |= (offset & 0x7FFFF) << 5;
310 }
311
312 if(mAssembly != NULL)
313 mAssembly->resize( int(pc()-base())*4 );
314
315 // the instruction cache is flushed by CodeCache
316 const int64_t duration = ggl_system_time() - mDuration;
317 const char * const format = "generated %s (%d ins) at [%p:%p] in %" PRId64 "ns\n";
318 ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
319
320
321 char value[PROPERTY_VALUE_MAX];
322 property_get("debug.pf.disasm", value, "0");
323 if (atoi(value) != 0)
324 {
325 printf(format, name, int(pc()-base()), base(), pc(), duration);
326 disassemble(name);
327 }
328 return OK;
329}
330
331uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
332{
333 return mLabels.valueFor(label);
334}
335
336// ----------------------------------------------------------------------------
337// Data Processing...
338// ----------------------------------------------------------------------------
339void ArmToArm64Assembler::dataProcessingCommon(int opcode,
340 int s, int Rd, int Rn, uint32_t Op2)
341{
342 if(opcode != opSUB && s == 1)
343 {
344 NOT_IMPLEMENTED(); //Not required
345 return;
346 }
347
348 if(opcode != opSUB && opcode != opADD && opcode != opAND &&
349 opcode != opORR && opcode != opMVN)
350 {
351 NOT_IMPLEMENTED(); //Not required
352 return;
353 }
354
355 if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_shift > 31)
356 {
357 NOT_IMPLEMENTED();
358 return;
359 }
360
361 //Store immediate in temporary register and convert
362 //immediate operation into register operation
363 if(Op2 == OPERAND_IMM)
364 {
365 int imm = mAddrMode.immediate;
366 *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0x0000FFFF, 0);
367 *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
368 Op2 = mTmpReg2;
369 }
370
371
372 {
373 uint32_t shift;
374 uint32_t amount;
375 uint32_t Rm;
376
377 if(Op2 == OPERAND_REG_IMM)
378 {
379 shift = mAddrMode.reg_imm_type;
380 amount = mAddrMode.reg_imm_shift;
381 Rm = mAddrMode.reg_imm_Rm;
382 }
383 else if(Op2 < OPERAND_REG)
384 {
385 shift = 0;
386 amount = 0;
387 Rm = Op2;
388 }
389 else
390 {
391 NOT_IMPLEMENTED(); //Not required
392 return;
393 }
394
395 switch(opcode)
396 {
397 case opADD: *mPC++ = A64_ADD_W(Rd, Rn, Rm, shift, amount); break;
398 case opAND: *mPC++ = A64_AND_W(Rd, Rn, Rm, shift, amount); break;
399 case opORR: *mPC++ = A64_ORR_W(Rd, Rn, Rm, shift, amount); break;
400 case opMVN: *mPC++ = A64_ORN_W(Rd, Rn, Rm, shift, amount); break;
401 case opSUB: *mPC++ = A64_SUB_W(Rd, Rn, Rm, shift, amount, s);break;
402 };
403
404 }
405}
406
407void ArmToArm64Assembler::dataProcessing(int opcode, int cc,
408 int s, int Rd, int Rn, uint32_t Op2)
409{
410 uint32_t Wd;
411
412 if(cc != AL)
413 Wd = mTmpReg1;
414 else
415 Wd = Rd;
416
417 if(opcode == opADD || opcode == opAND || opcode == opORR ||opcode == opSUB)
418 {
419 dataProcessingCommon(opcode, s, Wd, Rn, Op2);
420 }
421 else if(opcode == opCMP)
422 {
423 dataProcessingCommon(opSUB, 1, mTmpReg3, Rn, Op2);
424 }
425 else if(opcode == opRSB)
426 {
427 dataProcessingCommon(opSUB, s, Wd, Rn, Op2);
428 dataProcessingCommon(opSUB, s, Wd, mZeroReg, Wd);
429 }
430 else if(opcode == opMOV)
431 {
432 dataProcessingCommon(opORR, 0, Wd, mZeroReg, Op2);
433 if(s == 1)
434 {
435 dataProcessingCommon(opSUB, 1, mTmpReg3, Wd, mZeroReg);
436 }
437 }
438 else if(opcode == opMVN)
439 {
440 dataProcessingCommon(opMVN, s, Wd, mZeroReg, Op2);
441 }
442 else if(opcode == opBIC)
443 {
444 dataProcessingCommon(opMVN, s, mTmpReg3, mZeroReg, Op2);
445 dataProcessingCommon(opAND, s, Wd, Rn, mTmpReg3);
446 }
447 else
448 {
449 NOT_IMPLEMENTED();
450 return;
451 }
452
453 if(cc != AL)
454 {
455 *mPC++ = A64_CSEL_W(Rd, mTmpReg1, Rd, cc);
456 }
457}
458// ----------------------------------------------------------------------------
459// Address Processing...
460// ----------------------------------------------------------------------------
461
462void ArmToArm64Assembler::ADDR_ADD(int cc,
463 int s, int Rd, int Rn, uint32_t Op2)
464{
465 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
466 if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
467
468
469 if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSL)
470 {
471 int Rm = mAddrMode.reg_imm_Rm;
472 int amount = mAddrMode.reg_imm_shift;
473 *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
474 }
475 else if(Op2 < OPERAND_REG)
476 {
477 int Rm = Op2;
478 int amount = 0;
479 *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
480 }
481 else if(Op2 == OPERAND_IMM)
482 {
483 int imm = mAddrMode.immediate;
484 *mPC++ = A64_MOVZ_W(mTmpReg1, imm & 0x0000FFFF, 0);
485 *mPC++ = A64_MOVK_W(mTmpReg1, (imm >> 16) & 0x0000FFFF, 16);
486
487 int Rm = mTmpReg1;
488 int amount = 0;
489 *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
490 }
491 else
492 {
493 NOT_IMPLEMENTED(); //Not required
494 }
495}
496
497void ArmToArm64Assembler::ADDR_SUB(int cc,
498 int s, int Rd, int Rn, uint32_t Op2)
499{
500 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
501 if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
502
503 if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSR)
504 {
505 *mPC++ = A64_ADD_W(mTmpReg1, mZeroReg, mAddrMode.reg_imm_Rm,
506 LSR, mAddrMode.reg_imm_shift);
507 *mPC++ = A64_SUB_X_Wm_SXTW(Rd, Rn, mTmpReg1, 0);
508 }
509 else
510 {
511 NOT_IMPLEMENTED(); //Not required
512 }
513}
514
515// ----------------------------------------------------------------------------
516// multiply...
517// ----------------------------------------------------------------------------
518void ArmToArm64Assembler::MLA(int cc, int s,int Rd, int Rm, int Rs, int Rn)
519{
520 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
521
522 *mPC++ = A64_MADD_W(Rd, Rm, Rs, Rn);
523 if(s == 1)
524 dataProcessingCommon(opSUB, 1, mTmpReg1, Rd, mZeroReg);
525}
526void ArmToArm64Assembler::MUL(int cc, int s, int Rd, int Rm, int Rs)
527{
528 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
529 if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
530 *mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
531}
532void ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
533 int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
534{
535 NOT_IMPLEMENTED(); //Not required
536}
537void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
538 int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
539{
540 NOT_IMPLEMENTED(); //Not required
541}
542void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
543 int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
544{
545 NOT_IMPLEMENTED(); //Not required
546}
547void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
548 int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
549{
550 NOT_IMPLEMENTED(); //Not required
551}
552
553// ----------------------------------------------------------------------------
554// branches relative to PC...
555// ----------------------------------------------------------------------------
556void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
557 NOT_IMPLEMENTED(); //Not required
558}
559
560void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
561 NOT_IMPLEMENTED(); //Not required
562}
563
564void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
565 NOT_IMPLEMENTED(); //Not required
566}
567
568// ----------------------------------------------------------------------------
569// data transfer...
570// ----------------------------------------------------------------------------
571enum dataTransferOp
572{
573 opLDR,opLDRB,opLDRH,opSTR,opSTRB,opSTRH
574};
575
576void ArmToArm64Assembler::dataTransfer(int op, int cc,
577 int Rd, int Rn, uint32_t op_type, uint32_t size)
578{
579 const int XSP = 31;
580 if(Rn == SP)
581 Rn = XSP;
582
583 if(op_type == OPERAND_IMM)
584 {
585 int addrReg;
586 int imm = mAddrMode.immediate;
587 if(imm >= 0 && imm < (1<<12))
588 *mPC++ = A64_ADD_IMM_X(mTmpReg1, mZeroReg, imm, 0);
589 else if(imm < 0 && -imm < (1<<12))
590 *mPC++ = A64_SUB_IMM_X(mTmpReg1, mZeroReg, -imm, 0);
591 else
592 {
593 NOT_IMPLEMENTED();
594 return;
595 }
596
597 addrReg = Rn;
598 if(mAddrMode.preindex == true || mAddrMode.postindex == true)
599 {
600 *mPC++ = A64_ADD_X(mTmpReg2, addrReg, mTmpReg1);
601 if(mAddrMode.preindex == true)
602 addrReg = mTmpReg2;
603 }
604
605 if(cc != AL)
606 *mPC++ = A64_B_COND(cc^1, 8);
607
608 *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, addrReg, mZeroReg);
609
610 if(mAddrMode.writeback == true)
611 *mPC++ = A64_CSEL_X(Rn, mTmpReg2, Rn, cc);
612 }
613 else if(op_type == OPERAND_REG_OFFSET)
614 {
615 if(cc != AL)
616 *mPC++ = A64_B_COND(cc^1, 8);
617 *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mAddrMode.reg_offset);
618
619 }
620 else if(op_type > OPERAND_UNSUPPORTED)
621 {
622 if(cc != AL)
623 *mPC++ = A64_B_COND(cc^1, 8);
624 *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mZeroReg);
625 }
626 else
627 {
628 NOT_IMPLEMENTED(); // Not required
629 }
630 return;
631
632}
633void ArmToArm64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
634{
635 return dataTransfer(opLDR, cc, Rd, Rn, op_type, 64);
636}
637void ArmToArm64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
638{
639 return dataTransfer(opSTR, cc, Rd, Rn, op_type, 64);
640}
641void ArmToArm64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
642{
643 return dataTransfer(opLDR, cc, Rd, Rn, op_type);
644}
645void ArmToArm64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
646{
647 return dataTransfer(opLDRB, cc, Rd, Rn, op_type);
648}
649void ArmToArm64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
650{
651 return dataTransfer(opSTR, cc, Rd, Rn, op_type);
652}
653
654void ArmToArm64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
655{
656 return dataTransfer(opSTRB, cc, Rd, Rn, op_type);
657}
658
659void ArmToArm64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
660{
661 return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
662}
663void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
664{
665 NOT_IMPLEMENTED(); //Not required
666}
667void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
668{
669 NOT_IMPLEMENTED(); //Not required
670}
671
672void ArmToArm64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
673{
674 return dataTransfer(opSTRH, cc, Rd, Rn, op_type);
675}
676
677// ----------------------------------------------------------------------------
678// block data transfer...
679// ----------------------------------------------------------------------------
680void ArmToArm64Assembler::LDM(int cc, int dir,
681 int Rn, int W, uint32_t reg_list)
682{
683 const int XSP = 31;
684 if(cc != AL || dir != IA || W == 0 || Rn != SP)
685 {
686 NOT_IMPLEMENTED();
687 return;
688 }
689
690 for(int i = 0; i < 32; ++i)
691 {
692 if((reg_list & (1 << i)))
693 {
694 int reg = i;
695 int size = 16;
696 *mPC++ = A64_LDR_IMM_PostIndex(reg, XSP, size);
697 }
698 }
699}
700
701void ArmToArm64Assembler::STM(int cc, int dir,
702 int Rn, int W, uint32_t reg_list)
703{
704 const int XSP = 31;
705 if(cc != AL || dir != DB || W == 0 || Rn != SP)
706 {
707 NOT_IMPLEMENTED();
708 return;
709 }
710
711 for(int i = 31; i >= 0; --i)
712 {
713 if((reg_list & (1 << i)))
714 {
715 int size = -16;
716 int reg = i;
717 *mPC++ = A64_STR_IMM_PreIndex(reg, XSP, size);
718 }
719 }
720}
721
722// ----------------------------------------------------------------------------
723// special...
724// ----------------------------------------------------------------------------
725void ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
726{
727 NOT_IMPLEMENTED(); //Not required
728}
729void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
730{
731 NOT_IMPLEMENTED(); //Not required
732}
733void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
734{
735 NOT_IMPLEMENTED(); //Not required
736}
737
738// ----------------------------------------------------------------------------
739// DSP instructions...
740// ----------------------------------------------------------------------------
741void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
742 NOT_IMPLEMENTED(); //Not required
743}
744
745void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
746{
747 NOT_IMPLEMENTED(); //Not required
748}
749
750void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
751{
752 NOT_IMPLEMENTED(); //Not required
753}
754
755void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
756{
757 NOT_IMPLEMENTED(); //Not required
758}
759
760void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
761{
762 NOT_IMPLEMENTED(); //Not required
763}
764
765void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
766{
767 NOT_IMPLEMENTED(); //Not required
768}
769
770// ----------------------------------------------------------------------------
771// 16 x 16 multiplication
772// ----------------------------------------------------------------------------
773void ArmToArm64Assembler::SMUL(int cc, int xy,
774 int Rd, int Rm, int Rs)
775{
776 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
777
778 if (xy & xyTB)
779 *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 16, 31);
780 else
781 *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
782
783 if (xy & xyBT)
784 *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 16, 31);
785 else
786 *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
787
788 *mPC++ = A64_MADD_W(Rd,mTmpReg1,mTmpReg2, mZeroReg);
789}
790// ----------------------------------------------------------------------------
791// 32 x 16 multiplication
792// ----------------------------------------------------------------------------
793void ArmToArm64Assembler::SMULW(int cc, int y, int Rd, int Rm, int Rs)
794{
795 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
796
797 if (y & yT)
798 *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 16, 31);
799 else
800 *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 0, 15);
801
802 *mPC++ = A64_SBFM_W(mTmpReg2, Rm, 0, 31);
803 *mPC++ = A64_SMADDL(mTmpReg3,mTmpReg1,mTmpReg2, mZeroReg);
804 *mPC++ = A64_UBFM_X(Rd,mTmpReg3, 16, 47);
805}
806// ----------------------------------------------------------------------------
807// 16 x 16 multiplication and accumulate
808// ----------------------------------------------------------------------------
809void ArmToArm64Assembler::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn)
810{
811 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
812 if(xy != xyBB) { NOT_IMPLEMENTED(); return;} //Not required
813
814 *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
815 *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
816 *mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
817}
818
819void ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
820 int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
821{
822 NOT_IMPLEMENTED(); //Not required
823 return;
824}
825
826void ArmToArm64Assembler::SMLAW(int /*cc*/, int /*y*/,
827 int /*Rd*/, int /*Rm*/, int /*Rs*/, int /*Rn*/)
828{
829 NOT_IMPLEMENTED(); //Not required
830 return;
831}
832
833// ----------------------------------------------------------------------------
834// Byte/half word extract and extend
835// ----------------------------------------------------------------------------
836void ArmToArm64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate)
837{
838 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
839
840 *mPC++ = A64_EXTR_W(mTmpReg1, Rm, Rm, rotate * 8);
841
842 uint32_t imm = 0x00FF00FF;
843 *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0xFFFF, 0);
844 *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
845 *mPC++ = A64_AND_W(Rd,mTmpReg1, mTmpReg2);
846}
847
848// ----------------------------------------------------------------------------
849// Bit manipulation
850// ----------------------------------------------------------------------------
851void ArmToArm64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
852{
853 if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
854 *mPC++ = A64_UBFM_W(Rd, Rn, lsb, lsb + width - 1);
855}
856// ----------------------------------------------------------------------------
857// Shifters...
858// ----------------------------------------------------------------------------
859int ArmToArm64Assembler::buildImmediate(
860 uint32_t immediate, uint32_t& rot, uint32_t& imm)
861{
862 rot = 0;
863 imm = immediate;
864 return 0; // Always true
865}
866
867
868bool ArmToArm64Assembler::isValidImmediate(uint32_t immediate)
869{
870 uint32_t rot, imm;
871 return buildImmediate(immediate, rot, imm) == 0;
872}
873
874uint32_t ArmToArm64Assembler::imm(uint32_t immediate)
875{
876 mAddrMode.immediate = immediate;
877 mAddrMode.writeback = false;
878 mAddrMode.preindex = false;
879 mAddrMode.postindex = false;
880 return OPERAND_IMM;
881
882}
883
884uint32_t ArmToArm64Assembler::reg_imm(int Rm, int type, uint32_t shift)
885{
886 mAddrMode.reg_imm_Rm = Rm;
887 mAddrMode.reg_imm_type = type;
888 mAddrMode.reg_imm_shift = shift;
889 return OPERAND_REG_IMM;
890}
891
892uint32_t ArmToArm64Assembler::reg_rrx(int /*Rm*/)
893{
894 NOT_IMPLEMENTED();
895 return OPERAND_UNSUPPORTED;
896}
897
898uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
899{
900 NOT_IMPLEMENTED(); //Not required
901 return OPERAND_UNSUPPORTED;
902}
903// ----------------------------------------------------------------------------
904// Addressing modes...
905// ----------------------------------------------------------------------------
906uint32_t ArmToArm64Assembler::immed12_pre(int32_t immed12, int W)
907{
908 mAddrMode.immediate = immed12;
909 mAddrMode.writeback = W;
910 mAddrMode.preindex = true;
911 mAddrMode.postindex = false;
912 return OPERAND_IMM;
913}
914
915uint32_t ArmToArm64Assembler::immed12_post(int32_t immed12)
916{
917 mAddrMode.immediate = immed12;
918 mAddrMode.writeback = true;
919 mAddrMode.preindex = false;
920 mAddrMode.postindex = true;
921 return OPERAND_IMM;
922}
923
924uint32_t ArmToArm64Assembler::reg_scale_pre(int Rm, int type,
925 uint32_t shift, int W)
926{
927 if(type != 0 || shift != 0 || W != 0)
928 {
929 NOT_IMPLEMENTED(); //Not required
930 return OPERAND_UNSUPPORTED;
931 }
932 else
933 {
934 mAddrMode.reg_offset = Rm;
935 return OPERAND_REG_OFFSET;
936 }
937}
938
939uint32_t ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
940{
941 NOT_IMPLEMENTED(); //Not required
942 return OPERAND_UNSUPPORTED;
943}
944
945uint32_t ArmToArm64Assembler::immed8_pre(int32_t immed8, int W)
946{
947 mAddrMode.immediate = immed8;
948 mAddrMode.writeback = W;
949 mAddrMode.preindex = true;
950 mAddrMode.postindex = false;
951 return OPERAND_IMM;
952}
953
954uint32_t ArmToArm64Assembler::immed8_post(int32_t immed8)
955{
956 mAddrMode.immediate = immed8;
957 mAddrMode.writeback = true;
958 mAddrMode.preindex = false;
959 mAddrMode.postindex = true;
960 return OPERAND_IMM;
961}
962
963uint32_t ArmToArm64Assembler::reg_pre(int Rm, int W)
964{
965 if(W != 0)
966 {
967 NOT_IMPLEMENTED(); //Not required
968 return OPERAND_UNSUPPORTED;
969 }
970 else
971 {
972 mAddrMode.reg_offset = Rm;
973 return OPERAND_REG_OFFSET;
974 }
975}
976
977uint32_t ArmToArm64Assembler::reg_post(int /*Rm*/)
978{
979 NOT_IMPLEMENTED(); //Not required
980 return OPERAND_UNSUPPORTED;
981}
982
983// ----------------------------------------------------------------------------
984// A64 instructions
985// ----------------------------------------------------------------------------
986
987static __unused const char * dataTransferOpName[] =
988{
989 "LDR","LDRB","LDRH","STR","STRB","STRH"
990};
991
992static const uint32_t dataTransferOpCode [] =
993{
994 ((0xB8u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
995 ((0x38u << 24) | (0x3 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
996 ((0x78u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
997 ((0xB8u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
998 ((0x38u << 24) | (0x1 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
999 ((0x78u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11))
1000};
1001uint32_t ArmToArm64Assembler::A64_LDRSTR_Wm_SXTW_0(uint32_t op,
1002 uint32_t size, uint32_t Rt,
1003 uint32_t Rn, uint32_t Rm)
1004{
1005 if(size == 32)
1006 {
1007 LOG_INSTR("%s W%d, [X%d, W%d, SXTW #0]\n",
1008 dataTransferOpName[op], Rt, Rn, Rm);
1009 return(dataTransferOpCode[op] | (Rm << 16) | (Rn << 5) | Rt);
1010 }
1011 else
1012 {
1013 LOG_INSTR("%s X%d, [X%d, W%d, SXTW #0]\n",
1014 dataTransferOpName[op], Rt, Rn, Rm);
1015 return(dataTransferOpCode[op] | (0x1<<30) | (Rm<<16) | (Rn<<5)|Rt);
1016 }
1017}
1018
1019uint32_t ArmToArm64Assembler::A64_STR_IMM_PreIndex(uint32_t Rt,
1020 uint32_t Rn, int32_t simm)
1021{
1022 if(Rn == 31)
1023 LOG_INSTR("STR W%d, [SP, #%d]!\n", Rt, simm);
1024 else
1025 LOG_INSTR("STR W%d, [X%d, #%d]!\n", Rt, Rn, simm);
1026
1027 uint32_t imm9 = (unsigned)(simm) & 0x01FF;
1028 return (0xB8 << 24) | (imm9 << 12) | (0x3 << 10) | (Rn << 5) | Rt;
1029}
1030
1031uint32_t ArmToArm64Assembler::A64_LDR_IMM_PostIndex(uint32_t Rt,
1032 uint32_t Rn, int32_t simm)
1033{
1034 if(Rn == 31)
1035 LOG_INSTR("LDR W%d, [SP], #%d\n",Rt,simm);
1036 else
1037 LOG_INSTR("LDR W%d, [X%d], #%d\n",Rt, Rn, simm);
1038
1039 uint32_t imm9 = (unsigned)(simm) & 0x01FF;
1040 return (0xB8 << 24) | (0x1 << 22) |
1041 (imm9 << 12) | (0x1 << 10) | (Rn << 5) | Rt;
1042
1043}
1044uint32_t ArmToArm64Assembler::A64_ADD_X_Wm_SXTW(uint32_t Rd,
1045 uint32_t Rn,
1046 uint32_t Rm,
1047 uint32_t amount)
1048{
1049 LOG_INSTR("ADD X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
1050 return ((0x8B << 24) | (0x1 << 21) |(Rm << 16) |
1051 (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
1052
1053}
1054
1055uint32_t ArmToArm64Assembler::A64_SUB_X_Wm_SXTW(uint32_t Rd,
1056 uint32_t Rn,
1057 uint32_t Rm,
1058 uint32_t amount)
1059{
1060 LOG_INSTR("SUB X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
1061 return ((0xCB << 24) | (0x1 << 21) |(Rm << 16) |
1062 (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
1063
1064}
1065
1066uint32_t ArmToArm64Assembler::A64_B_COND(uint32_t cc, uint32_t offset)
1067{
1068 LOG_INSTR("B.%s #.+%d\n", cc_codes[cc], offset);
1069 return (0x54 << 24) | ((offset/4) << 5) | (cc);
1070
1071}
1072uint32_t ArmToArm64Assembler::A64_ADD_X(uint32_t Rd, uint32_t Rn,
1073 uint32_t Rm, uint32_t shift,
1074 uint32_t amount)
1075{
1076 LOG_INSTR("ADD X%d, X%d, X%d, %s #%d\n",
1077 Rd, Rn, Rm, shift_codes[shift], amount);
1078 return ((0x8B << 24) | (shift << 22) | ( Rm << 16) |
1079 (amount << 10) |(Rn << 5) | Rd);
1080}
1081uint32_t ArmToArm64Assembler::A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
1082 uint32_t imm, uint32_t shift)
1083{
1084 LOG_INSTR("ADD X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
1085 return (0x91 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
1086}
1087
1088uint32_t ArmToArm64Assembler::A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
1089 uint32_t imm, uint32_t shift)
1090{
1091 LOG_INSTR("SUB X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
1092 return (0xD1 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
1093}
1094
1095uint32_t ArmToArm64Assembler::A64_ADD_W(uint32_t Rd, uint32_t Rn,
1096 uint32_t Rm, uint32_t shift,
1097 uint32_t amount)
1098{
1099 LOG_INSTR("ADD W%d, W%d, W%d, %s #%d\n",
1100 Rd, Rn, Rm, shift_codes[shift], amount);
1101 return ((0x0B << 24) | (shift << 22) | ( Rm << 16) |
1102 (amount << 10) |(Rn << 5) | Rd);
1103}
1104
1105uint32_t ArmToArm64Assembler::A64_SUB_W(uint32_t Rd, uint32_t Rn,
1106 uint32_t Rm, uint32_t shift,
1107 uint32_t amount,
1108 uint32_t setflag)
1109{
1110 if(setflag == 0)
1111 {
1112 LOG_INSTR("SUB W%d, W%d, W%d, %s #%d\n",
1113 Rd, Rn, Rm, shift_codes[shift], amount);
1114 return ((0x4B << 24) | (shift << 22) | ( Rm << 16) |
1115 (amount << 10) |(Rn << 5) | Rd);
1116 }
1117 else
1118 {
1119 LOG_INSTR("SUBS W%d, W%d, W%d, %s #%d\n",
1120 Rd, Rn, Rm, shift_codes[shift], amount);
1121 return ((0x6B << 24) | (shift << 22) | ( Rm << 16) |
1122 (amount << 10) |(Rn << 5) | Rd);
1123 }
1124}
1125
1126uint32_t ArmToArm64Assembler::A64_AND_W(uint32_t Rd, uint32_t Rn,
1127 uint32_t Rm, uint32_t shift,
1128 uint32_t amount)
1129{
1130 LOG_INSTR("AND W%d, W%d, W%d, %s #%d\n",
1131 Rd, Rn, Rm, shift_codes[shift], amount);
1132 return ((0x0A << 24) | (shift << 22) | ( Rm << 16) |
1133 (amount << 10) |(Rn << 5) | Rd);
1134}
1135
1136uint32_t ArmToArm64Assembler::A64_ORR_W(uint32_t Rd, uint32_t Rn,
1137 uint32_t Rm, uint32_t shift,
1138 uint32_t amount)
1139{
1140 LOG_INSTR("ORR W%d, W%d, W%d, %s #%d\n",
1141 Rd, Rn, Rm, shift_codes[shift], amount);
1142 return ((0x2A << 24) | (shift << 22) | ( Rm << 16) |
1143 (amount << 10) |(Rn << 5) | Rd);
1144}
1145
1146uint32_t ArmToArm64Assembler::A64_ORN_W(uint32_t Rd, uint32_t Rn,
1147 uint32_t Rm, uint32_t shift,
1148 uint32_t amount)
1149{
1150 LOG_INSTR("ORN W%d, W%d, W%d, %s #%d\n",
1151 Rd, Rn, Rm, shift_codes[shift], amount);
1152 return ((0x2A << 24) | (shift << 22) | (0x1 << 21) | ( Rm << 16) |
1153 (amount << 10) |(Rn << 5) | Rd);
1154}
1155
1156uint32_t ArmToArm64Assembler::A64_CSEL_X(uint32_t Rd, uint32_t Rn,
1157 uint32_t Rm, uint32_t cond)
1158{
1159 LOG_INSTR("CSEL X%d, X%d, X%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
1160 return ((0x9A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
1161}
1162
1163uint32_t ArmToArm64Assembler::A64_CSEL_W(uint32_t Rd, uint32_t Rn,
1164 uint32_t Rm, uint32_t cond)
1165{
1166 LOG_INSTR("CSEL W%d, W%d, W%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
1167 return ((0x1A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
1168}
1169
1170uint32_t ArmToArm64Assembler::A64_RET(uint32_t Rn)
1171{
1172 LOG_INSTR("RET X%d\n", Rn);
1173 return ((0xD6 << 24) | (0x1 << 22) | (0x1F << 16) | (Rn << 5));
1174}
1175
1176uint32_t ArmToArm64Assembler::A64_MOVZ_X(uint32_t Rd, uint32_t imm,
1177 uint32_t shift)
1178{
1179 LOG_INSTR("MOVZ X%d, #0x%x, LSL #%d\n", Rd, imm, shift);
1180 return(0xD2 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
1181}
1182
1183uint32_t ArmToArm64Assembler::A64_MOVK_W(uint32_t Rd, uint32_t imm,
1184 uint32_t shift)
1185{
1186 LOG_INSTR("MOVK W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
1187 return (0x72 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
1188}
1189
1190uint32_t ArmToArm64Assembler::A64_MOVZ_W(uint32_t Rd, uint32_t imm,
1191 uint32_t shift)
1192{
1193 LOG_INSTR("MOVZ W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
1194 return(0x52 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
1195}
1196
1197uint32_t ArmToArm64Assembler::A64_SMADDL(uint32_t Rd, uint32_t Rn,
1198 uint32_t Rm, uint32_t Ra)
1199{
1200 LOG_INSTR("SMADDL X%d, W%d, W%d, X%d\n",Rd, Rn, Rm, Ra);
1201 return ((0x9B << 24) | (0x1 << 21) | (Rm << 16)|(Ra << 10)|(Rn << 5) | Rd);
1202}
1203
1204uint32_t ArmToArm64Assembler::A64_MADD_W(uint32_t Rd, uint32_t Rn,
1205 uint32_t Rm, uint32_t Ra)
1206{
1207 LOG_INSTR("MADD W%d, W%d, W%d, W%d\n",Rd, Rn, Rm, Ra);
1208 return ((0x1B << 24) | (Rm << 16) | (Ra << 10) |(Rn << 5) | Rd);
1209}
1210
1211uint32_t ArmToArm64Assembler::A64_SBFM_W(uint32_t Rd, uint32_t Rn,
1212 uint32_t immr, uint32_t imms)
1213{
1214 LOG_INSTR("SBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
1215 return ((0x13 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
1216
1217}
1218uint32_t ArmToArm64Assembler::A64_UBFM_W(uint32_t Rd, uint32_t Rn,
1219 uint32_t immr, uint32_t imms)
1220{
1221 LOG_INSTR("UBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
1222 return ((0x53 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
1223
1224}
1225uint32_t ArmToArm64Assembler::A64_UBFM_X(uint32_t Rd, uint32_t Rn,
1226 uint32_t immr, uint32_t imms)
1227{
1228 LOG_INSTR("UBFM X%d, X%d, #%d, #%d\n", Rd, Rn, immr, imms);
1229 return ((0xD3 << 24) | (0x1 << 22) |
1230 (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
1231
1232}
1233uint32_t ArmToArm64Assembler::A64_EXTR_W(uint32_t Rd, uint32_t Rn,
1234 uint32_t Rm, uint32_t lsb)
1235{
1236 LOG_INSTR("EXTR W%d, W%d, W%d, #%d\n", Rd, Rn, Rm, lsb);
1237 return (0x13 << 24)|(0x1 << 23) | (Rm << 16) | (lsb << 10)|(Rn << 5) | Rd;
1238}
1239
1240}; // namespace android