Fixing generation of arithmetic expressions:
[dyninst.git] / dyninstAPI / src / codegen-aarch64.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  *
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include <stdlib.h>
32 #include "dyninstAPI/src/codegen.h"
33 #include "dyninstAPI/src/debug.h"
34 #include "dyninstAPI/src/instPoint.h"
35 #include "dyninstAPI/src/registerSpace.h"
36 #include "dyninstAPI/src/addressSpace.h"
37 #include "dyninstAPI/src/inst-aarch64.h"
38 #include "dyninstAPI/src/emit-aarch64.h"
39 #include "dyninstAPI/src/function.h"
40
41 #if defined(os_vxworks)
42 #include "common/src/wtxKludges.h"
43 #endif
44
45
46 // "Casting" methods. We use a "base + offset" model, but often need to
47 // turn that into "current instruction pointer".
48 codeBuf_t *insnCodeGen::insnPtr(codeGen &gen) {
49     return (instructUnion *)gen.cur_ptr();
50 }
51
52 #if 0
53 // Same as above, but increment offset to point at the next insn.
54 codeBuf_t *insnCodeGen::ptrAndInc(codeGen &gen) {
55   // MAKE SURE THAT ret WILL STAY VALID!
56   gen.realloc(gen.used() + sizeof(instruction));
57
58   instructUnion *ret = insnPtr(gen);
59   gen.moveIndex(instruction::size());
60   return ret;
61 }
62 #endif
63
64 void insnCodeGen::generate(codeGen &gen, instruction &insn) {
65 #if defined(endian_mismatch)
66   // Writing an instruction.  Convert byte order if necessary.
67   unsigned raw = swapBytesIfNeeded(insn.asInt());
68 #else
69   unsigned raw = insn.asInt();
70 #endif
71
72   gen.copy(&raw, sizeof(unsigned));
73 }
74
75 void insnCodeGen::generate(codeGen &gen, instruction &insn, unsigned position) {
76 #if defined(endian_mismatch)
77     // Writing an instruction.  Convert byte order if necessary.
78     unsigned raw = swapBytesIfNeeded(insn.asInt());
79 #else
80     unsigned raw = insn.asInt();
81 #endif
82
83     gen.insert(&raw, sizeof(unsigned), position);
84 }
85
86 void insnCodeGen::generateIllegal(codeGen &gen) { // instP.h
87     instruction insn;
88     generate(gen,insn);
89 }
90
91 void insnCodeGen::generateTrap(codeGen &gen) {
92     instruction insn(BREAK_POINT_INSN);
93     generate(gen,insn);
94 }
95
96 void insnCodeGen::generateBranch(codeGen &gen, long disp, bool link) {
97     if (labs(disp) > MAX_BRANCH_OFFSET) {
98         fprintf(stderr, "ABS OFF: 0x%lx, MAX: 0x%lx\n",
99                 labs(disp), (unsigned long) MAX_BRANCH_OFFSET);
100         bperr( "Error: attempted a branch of 0x%lx\n", disp);
101         logLine("a branch too far\n");
102         showErrorCallback(52, "Internal error: branch too far");
103         bperr( "Attempted to make a branch of offset 0x%lx\n", disp);
104         assert(0);
105     }
106
107     instruction insn;
108     INSN_SET(insn, 26, 30, BOp);
109     //Set the displacement immediate
110     INSN_SET(insn, 0, 25, disp >> 2);
111
112     //Bit 31 is set if it's a branch-and-link (essentially, a call), unset if it's just a branch
113     if(link)
114         INSN_SET(insn, 31, 31, 1);
115     else
116         INSN_SET(insn, 31, 31, 0);
117
118     insnCodeGen::generate(gen, insn);
119 }
120
121 void insnCodeGen::generateBranch(codeGen &gen, Address from, Address to, bool link) {
122     long disp = (to - from);
123
124     if (labs(disp) > MAX_BRANCH_OFFSET) {
125         generateLongBranch(gen, from, to, link);
126     }else
127         generateBranch(gen, disp, link);
128 }
129
130 void insnCodeGen::generateCall(codeGen &gen, Address from, Address to) {
131     generateBranch(gen, from, to, true);
132 }
133
134 void insnCodeGen::generateLongBranch(codeGen &gen,
135                                      Address from,
136                                      Address to,
137                                      bool isCall) 
138 {
139     Register scratch = REG_NULL;
140
141     instPoint *point = gen.point();
142     if(!point)
143     {
144         if(!isCall)
145         {
146             //scratch = 14; //#sasha hard coding register for springboard
147             assert(gen.rs());
148             scratch = gen.rs()->getScratchRegister(gen);
149         }
150         else
151         {
152             generateBranchViaTrap(gen, from, to, isCall);
153             return;
154         }
155     }
156     else
157     {
158         registerSpace *rs = registerSpace::actualRegSpace(point);
159         gen.setRegisterSpace(rs);
160
161         scratch = rs->getScratchRegister(gen, true);
162         if (scratch == REG_NULL)
163         {
164             fprintf(stderr, " %s[%d] No registers. Calling generateBranchViaTrap...\n", FILE__, __LINE__);
165             generateBranchViaTrap(gen, from, to, isCall);
166             return;
167         }
168     }
169
170     insnCodeGen::loadImmIntoReg<Address>(gen, scratch, to);
171
172     instruction branchInsn;
173     branchInsn.clear();
174
175     //Set bits which are 0 for both BR and BLR
176     INSN_SET(branchInsn, 0, 4, 0);
177     INSN_SET(branchInsn, 10, 15, 0);
178
179     //Set register
180     INSN_SET(branchInsn, 5, 9, scratch);
181
182     // Set other bits . Basically, these are the opcode bits. 
183     // The only difference between BR and BLR is that bit 21 is 1 for BLR.
184     INSN_SET(branchInsn, 16, 31, BRegOp);
185     if(isCall)
186         INSN_SET(branchInsn, 21, 21, 1);
187
188     insnCodeGen::generate(gen, branchInsn);
189 }
190
191 void insnCodeGen::generateBranchViaTrap(codeGen &gen, Address from, Address to, bool isCall) {
192     long disp = to - from;
193     if (labs(disp) <= MAX_BRANCH_OFFSET) {
194         // We shouldn't be here, since this is an internal-called-only func.
195         generateBranch(gen, disp, isCall);
196     }
197
198     assert (!isCall); // Can't do this yet
199
200     if (gen.addrSpace()) {
201         // Too far to branch.  Use trap-based instrumentation.
202         gen.addrSpace()->trapMapping.addTrapMapping(from, to, true);
203         insnCodeGen::generateTrap(gen);
204     } else {
205         // Too far to branch and no proc to register trap.
206         fprintf(stderr, "ABS OFF: 0x%lx, MAX: 0x%lx\n",
207                 labs(disp), (unsigned long) MAX_BRANCH_OFFSET);
208         bperr( "Error: attempted a branch of 0x%lx\n", disp);
209         logLine("a branch too far\n");
210         showErrorCallback(52, "Internal error: branch too far");
211         bperr( "Attempted to make a branch of offset 0x%lx\n", disp);
212         assert(0);
213     }
214 }
215
216 void insnCodeGen::generateConditionalBranch(codeGen& gen, Address to, unsigned opcode)
217 {
218     instruction insn;
219     insn.clear();
220
221     //Set opcode
222     INSN_SET(insn, 25, 31, BCondOp);
223
224     //Set imm19 field
225     INSN_SET(insn, 5, 23, to >> 2);
226
227     auto getConditionCode = [&opcode]() -> unsigned
228     {
229         switch(opcode){
230             case lessOp:    return 0xB;
231             case leOp:      return 0xD;
232             case greaterOp: return 0xC;
233             case geOp:      return 0xA;
234             case eqOp:      return 0x0;
235             case neOp:      return 0x1;
236             default:
237                 assert(0); // wrong condition passed
238                 break;
239         }
240     };
241
242     //Set condition 
243     INSN_SET(insn, 0, 3, getConditionCode());
244
245     insnCodeGen::generate(gen, insn);
246 }
247
248
249 void insnCodeGen::generateAddSubShifted(
250         codeGen &gen, insnCodeGen::ArithOp op, int shift, int imm6, Register rm, 
251         Register rn, Register rd, bool is64bit) 
252 {
253     instruction insn;
254     insn.clear();
255
256     //Set bit 31 to 1 if using 64-bit registers
257     if(is64bit)
258         INSN_SET(insn, 31, 31, 1);
259     //Set opcode
260     INSN_SET(insn, 24, 30, op == Add ? ADDShiftOp : SUBShiftOp);
261
262     //Set shift field
263     assert(shift >= 0 && shift <= 3);
264     INSN_SET(insn, 22, 23, (shift & 0x3));
265
266     //Set imm6 field
267     assert(imm6 >= 0 && imm6 < (is64bit ? 64 : 32));
268     INSN_SET(insn, 10, 15, imm6);
269
270     //Set registers
271     INSN_SET(insn, 0, 4, rd);
272     INSN_SET(insn, 5, 9, rn);
273     INSN_SET(insn, 16, 20, rm);
274
275     insnCodeGen::generate(gen, insn);
276 }
277
278 void insnCodeGen::generateAddSubImmediate(
279         codeGen &gen, insnCodeGen::ArithOp op, int shift, int imm12, Register rn, Register rd, bool is64bit) 
280 {
281     instruction insn;
282     insn.clear();
283
284     //Set bit 31 to 1 if using 64-bit registers
285     if(is64bit)
286         INSN_SET(insn, 31, 31, 1);
287     //Set opcode
288     INSN_SET(insn, 24, 30, op == Add ? ADDImmOp : SUBImmOp);
289
290     //Set shift field
291     assert(shift >= 0 && shift <= 3);
292     INSN_SET(insn, 22, 23, (shift & 0x3));
293
294     //Set imm12 field
295     INSN_SET(insn, 10, 21, imm12);
296
297     //Set registers
298     INSN_SET(insn, 5, 9, rn);
299     INSN_SET(insn, 0, 4, rd);
300
301     insnCodeGen::generate(gen, insn);
302 }
303
304 void insnCodeGen::generateMul(codeGen &gen, Register rm, Register rn, Register rd, bool is64bit) {
305     instruction insn;
306     insn.clear();
307
308     //Set bit 31 to 1 if using 64-bit registers
309     if(is64bit)
310         INSN_SET(insn, 31, 31, 1);
311     //Set opcode
312     INSN_SET(insn, 21, 28, MULOp);
313
314     //Bits 10 to 14 are 1 for MUL
315     INSN_SET(insn, 10, 14, 0x1F);
316
317     //Set registers
318     INSN_SET(insn, 16, 20, rm);
319     INSN_SET(insn, 5, 9, rn);
320     INSN_SET(insn, 0, 4, rd);
321
322     insnCodeGen::generate(gen, insn);
323 }
324
325 //#sasha is rm or rn the denominator?
326 void insnCodeGen::generateDiv(
327         codeGen &gen, Register rm, Register rn, Register rd, bool is64bit)
328 {
329     instruction insn;
330     insn.clear();
331
332     // Set bit 31 to 1 if using 64-bit registers
333     if(is64bit)
334         INSN_SET(insn, 31, 31, 1);
335
336     // Set opcode
337     INSN_SET(insn, 21, 30, SDIVOp);
338
339     INSN_SET(insn, 11, 15, 0x1);
340     INSN_SET(insn, 10, 10, 0x0); // signed: SDIV
341
342     //Set registers
343     INSN_SET(insn, 16, 20, rm);
344     INSN_SET(insn, 5, 9, rn);
345     INSN_SET(insn, 0, 4, rd);
346
347     insnCodeGen::generate(gen, insn);
348
349 }
350
351 void insnCodeGen::generateBitwiseOpShifted(
352         codeGen &gen, insnCodeGen::BitwiseOp op, int shift, Register rm, int imm6, 
353         Register rn, Register rd, bool is64bit) 
354 {
355     instruction insn;
356     insn.clear();
357
358     //Set bit 31 to 1 if using 64-bit registers
359     if(is64bit)
360         INSN_SET(insn, 31, 31, 1);
361
362     //Set opcode
363     int opcode;
364     switch(op) {
365         case insnCodeGen::And: opcode = ANDShiftOp;
366             break;
367         case insnCodeGen::Or: opcode = ORRShiftOp;
368             break;
369         case insnCodeGen::Eor: opcode = EORShiftOp;
370             break;
371     }
372     INSN_SET(insn, 24, 30, opcode);
373
374     //Set shift field
375     assert(shift >= 0 && shift <= 3);
376     INSN_SET(insn, 22, 23, (shift & 0x3));
377
378     //Set imm6 field
379     assert(imm6 >= 0 && imm6 < (is64bit ? 64 : 32));
380     INSN_SET(insn, 10, 15, imm6);
381
382     //Set registers
383     INSN_SET(insn, 16, 20, rm);
384     INSN_SET(insn, 5, 9, rn);
385     INSN_SET(insn, 0, 4, rd);
386
387     insnCodeGen::generate(gen, insn);
388 }
389
390 void insnCodeGen::generateLoadReg(codeGen &gen, Register rt,
391                                   Register ra, Register rb)
392 {
393     assert(0);
394 //#warning "This function is not implemented yet!"
395 }
396
397 void insnCodeGen::generateStoreReg(codeGen &gen, Register rt,
398                                    Register ra, Register rb)
399 {
400     assert(0);
401 //#warning "This function is not implemented yet!"
402 }
403
404 void insnCodeGen::generateLoadReg64(codeGen &gen, Register rt,
405                                     Register ra, Register rb)
406 {
407 assert(0);
408 //#warning "This function is not implemented yet!"
409 }
410
411 void insnCodeGen::generateStoreReg64(codeGen &gen, Register rs,
412                                      Register ra, Register rb)
413 {
414 assert(0);
415 //#warning "This function is not implemented yet!"
416 }
417
418 void insnCodeGen::generateMove(codeGen &gen, int imm16, int shift, Register rd, MoveOp movOp)
419 {
420     instruction insn;
421     insn.clear();
422
423     //Set the sf bit to 1 since we always want to use 64-bit registers
424     INSN_SET(insn, 31, 31, 1);
425
426     //Set opcode
427     INSN_SET(insn, 23, 30, movOp);
428
429     //Set immediate
430     INSN_SET(insn, 5, 20, imm16);
431
432     //Set register
433     INSN_SET(insn, 0, 4, rd);
434
435     //Set shift amount for immediate
436     INSN_SET(insn, 21, 22, (shift & 0x3));
437
438     insnCodeGen::generate(gen, insn);
439 }
440
441 void insnCodeGen::generateMove(
442         codeGen &gen, Register rd, Register rm, bool is64bit)
443 {
444     insnCodeGen::generateBitwiseOpShifted(gen, insnCodeGen::Or, 0, rm, 0, 0x1f, rd, is64bit);  
445 }
446
447 void insnCodeGen::generateMoveSP(codeGen &gen, Register rn, Register rd, bool is64bit) {
448     instruction insn;
449     insn.clear();
450
451     //Set source and destination registers
452     INSN_SET(insn, 0, 4, rd & 0x1f);
453     INSN_SET(insn, 5, 9, rn & 0x1f);
454
455     //Set opcode
456     INSN_SET(insn, 10, 30, MOVSPOp);
457
458     //Set if using 64-bit registers
459     INSN_SET(insn, 31, 31, is64bit);
460
461     insnCodeGen::generate(gen, insn);
462 }
463
464
465 Register insnCodeGen::moveValueToReg(codeGen &gen, long int val, pdvector<Register> *exclude) {
466     Register scratchReg;
467     if(exclude)
468             scratchReg = gen.rs()->getScratchRegister(gen, *exclude, true);
469     else
470             scratchReg = gen.rs()->getScratchRegister(gen, true);
471
472     if (scratchReg == REG_NULL) {
473         fprintf(stderr, " %s[%d] No scratch register available to generate add instruction!", FILE__, __LINE__);
474         assert(0);
475     }
476
477     insnCodeGen::generateMove(gen, (val & 0xFFFF), 0, scratchReg, insnCodeGen::MovOp_MOVZ);
478     if (val >= MIN_IMM32 && val < MAX_IMM32)
479         insnCodeGen::generateMove(gen, ((val >> 16) & 0xFFFF), 0x1, scratchReg, insnCodeGen::MovOp_MOVK);
480     if (val < MIN_IMM32 || val > MAX_IMM32) {
481         insnCodeGen::generateMove(gen, ((val >> 32) & 0xFFFF), 0x2, scratchReg, insnCodeGen::MovOp_MOVK);
482         insnCodeGen::generateMove(gen, ((val >> 48) & 0xFFFF), 0x3, scratchReg, insnCodeGen::MovOp_MOVK);
483     }
484
485     return scratchReg;
486 }
487
488 // This is for generating STR/LDR (imediate) for indexing modes of Post, Pre and Offset
489 void insnCodeGen::generateMemAccess32or64(codeGen &gen, LoadStore accType,
490         Register r1, Register r2, int immd, bool is64bit, IndexMode im)
491 {
492     instruction insn;
493     insn.clear();
494
495     //Bit 31 is always 1. Bit 30 is 1 if we're using the 64-bit variant.
496     INSN_SET(insn, 31, 31, 1);
497     if(is64bit)
498         INSN_SET(insn, 30, 30, 1);
499
500     switch(im){
501         case Post:
502         case Pre:
503             //Set opcode, index and offset bits
504             if(immd >= -256 && immd <= 255) {
505                 INSN_SET(insn, 21, 29, (accType == Load) ? LDRImmOp : STRImmOp);
506                 INSN_SET(insn, 10, 11, im==Post?0x1:0x3);
507                 INSN_SET(insn, 12, 20, immd);
508             } else {
509                 assert(!"Cannot perform a post/pre-indexed memory access for offsets not in range [-256, 255]!");
510             }
511             break;
512         case Offset:
513             INSN_SET(insn, 22, 29, (accType == Load) ? LDRImmUIOp : STRImmUIOp);
514             assert(immd>=0); // this offset is supposed to unsigned, i.e. positive
515             INSN_SET(insn, 10, 21, immd>>3);
516             break;
517     }
518
519     //Set memory access register and register for address calculation.
520     INSN_SET(insn, 0, 4, r1 & 0x1F);
521     INSN_SET(insn, 5, 9, r2 & 0x1F);
522
523     insnCodeGen::generate(gen, insn);
524 }
525
526 void insnCodeGen::generateMemAccessFP(codeGen &gen, LoadStore accType,
527         Register rt, Register rn, int immd, int size, bool is128bit)
528 {
529     instruction insn;
530     insn.clear();
531
532     if(size < 0 || size > 3)
533         assert(!"Size field for STR (immediate, SIMD&FP) variant has to be in the range [0-3]!");
534
535     //Set size, opcode, index and offset bits
536     INSN_SET(insn, 30, 31, size & 0x3);
537     INSN_SET(insn, 21, 29, (accType == Load) ? LDRFPImmOp : STRFPImmOp);
538     if(is128bit)
539         INSN_SET(insn, 23, 23, 1);
540     INSN_SET(insn, 10, 11, 0x1);
541     if(immd >= -256 && immd <= 255) {
542         INSN_SET(insn, 12, 20, immd);
543     } else {
544         assert(!"Cannot perform a post-indexed memory access for offsets not in range [-256, 255]!");
545     }
546
547     //Set memory access register and register for address calculation.
548     INSN_SET(insn, 0, 4, rt);
549     INSN_SET(insn, 5, 9, rn);
550
551     insnCodeGen::generate(gen, insn);
552 }
553
554 // rlwinm ra,rs,n,0,31-n
555 void insnCodeGen::generateLShift(codeGen &gen, Register rs, int shift, Register ra)
556 {
557 assert(0);
558 //#warning "This function is not implemented yet!"
559 }
560
561 // rlwinm ra,rs,32-n,n,31
562 void insnCodeGen::generateRShift(codeGen &gen, Register rs, int shift, Register ra)
563 {
564 assert(0);
565 //#warning "This function is not implemented yet!"
566 }
567
568 // sld ra, rs, rb
569 void insnCodeGen::generateLShift64(codeGen &gen, Register rs, int shift, Register ra)
570 {
571 assert(0);
572 //#warning "This function is not implemented yet!"
573 }
574
575 // srd ra, rs, rb
576 void insnCodeGen::generateRShift64(codeGen &gen, Register rs, int shift, Register ra)
577 {
578 assert(0);
579 //not implemented
580 }
581
582 //
583 // generate an instruction that does nothing and has to side affect except to
584 //   advance the program counter.
585 //
586 void insnCodeGen::generateNOOP(codeGen &gen, unsigned size) {
587     assert((size % instruction::size()) == 0);
588     while (size) {
589         instruction insn(NOOP);
590         insnCodeGen::generate(gen, insn);
591         size -= instruction::size();
592     }
593 }
594
595 void insnCodeGen::generateSimple(codeGen &gen, int op,
596                                  Register src1, Register src2,
597                                  Register dest)
598 {
599 assert(0);
600 //#warning "This function is not implemented yet!"
601 }
602
603 void insnCodeGen::generateRelOp(codeGen &gen, int cond, int mode, Register rs1,
604                                 Register rs2, Register rd)
605 {
606 assert(0);
607 //#warning "This function is not implemented yet!"
608 }
609
610 template <typename T>
611 void insnCodeGen::loadImmIntoReg(codeGen &gen, Register rt, T value)
612 {
613     assert(value >= 0);
614
615     insnCodeGen::generateMove(gen, (value & 0xFFFF), 0, rt, MovOp_MOVZ);
616     if(value > 0xFFFF)
617         insnCodeGen::generateMove(gen, ((value >> 16) & 0xFFFF), 0x1, rt, MovOp_MOVK);
618     if(value > 0xFFFFFFFF)
619         insnCodeGen::generateMove(gen, ((value >> 32) & 0xFFFF), 0x2, rt, MovOp_MOVK);
620     if(value > 0xFFFFFFFFFFFF)
621         insnCodeGen::generateMove(gen, ((value >> 48) & 0xFFFF), 0x3, rt, MovOp_MOVK);
622 }
623
624
625 void insnCodeGen::saveRegister(codeGen &gen, Register r)
626 {
627     generateAddSubImmediate(gen, Sub, 0, 16, REG_SP, REG_SP, true);
628     generateMemAccess32or64(gen, insnCodeGen::Store, r, REG_SP, /*-2*GPRSIZE_64*/ 0, true);
629 }
630
631
632 void insnCodeGen::restoreRegister(codeGen &gen, Register r)
633 {
634     generateMemAccess32or64(gen, insnCodeGen::Load, r, REG_SP, /*2*GPRSIZE_64*/ 0, true);
635     generateAddSubImmediate(gen, Add, 0, 16, REG_SP, REG_SP, true);
636 }
637
638
639 // Helper method.  Fills register with partial value to be completed
640 // by an operation with a 16-bit signed immediate.  Such as loads and
641 // stores.
642 void insnCodeGen::loadPartialImmIntoReg(codeGen &gen, Register rt, long value)
643 {
644 assert(0);
645 //#warning "This function is not implemented yet!"
646 }
647
648 int insnCodeGen::createStackFrame(codeGen &gen, int numRegs, pdvector<Register>& freeReg, pdvector<Register>& excludeReg){
649 assert(0);
650 //#warning "This function is not implemented yet!"
651                 return freeReg.size();
652 }
653
654 void insnCodeGen::removeStackFrame(codeGen &gen) {
655 assert(0);
656 //#warning "This function is not implemented yet!"
657 }
658
659 bool insnCodeGen::generate(codeGen &gen,
660                            instruction &insn,
661                            AddressSpace * /*proc*/,
662                            Address /*origAddr*/,
663                            Address /*relocAddr*/,
664                            patchTarget * /*fallthroughOverride*/,
665                            patchTarget * /*targetOverride*/) {
666   assert(0 && "Deprecated!");
667   return false;
668 }
669
670 bool insnCodeGen::generateMem(codeGen &,
671                               instruction&,
672                               Address,
673                               Address,
674                               Register,
675                   Register) {
676 assert(0);
677 //#warning "This function is not implemented yet!"
678 return false; }
679
680 void insnCodeGen::generateMoveFromLR(codeGen &gen, Register rt) {
681 assert(0);
682 //#warning "This function is not implemented yet!"
683 }
684
685 void insnCodeGen::generateMoveToLR(codeGen &gen, Register rs) {
686 assert(0);
687 //#warning "This function is not implemented yet!"
688 }
689 void insnCodeGen::generateMoveToCR(codeGen &gen, Register rs) {
690 assert(0);
691 //#warning "This function is not implemented yet!"
692 }
693
694 bool insnCodeGen::modifyJump(Address target,
695                              NS_aarch64::instruction &insn,
696                              codeGen &gen) {
697     long disp = target - gen.currAddr();
698
699     if(INSN_GET_ISCALL(insn))
700     {
701         generateBranch(gen, gen.currAddr(), target, INSN_GET_ISCALL(insn));
702         return true;
703     }
704
705     if (labs(disp) > MAX_BRANCH_OFFSET) {
706         generateBranchViaTrap(gen, gen.currAddr(), target, INSN_GET_ISCALL(insn));
707         return true;
708     }
709
710     generateBranch(gen,
711                    gen.currAddr(),
712                    target,
713                    INSN_GET_ISCALL(insn));
714     return true;
715 }
716
717 /* TODO and/or FIXME
718  * The logic used by this function is common across architectures but is replicated 
719  * in architecture-specific manner in all codegen-* files.
720  * This means that the logic itself needs to be refactored into the (platform 
721  * independent) codegen.C file. Appropriate architecture-specific,
722  * bit-twiddling functions can then be defined if necessary in the codegen-* files 
723  * and called as necessary by the common, refactored logic.
724 */
725 bool insnCodeGen::modifyJcc(Address target,
726                             NS_aarch64::instruction &insn,
727                             codeGen &gen) {
728     long disp = target - gen.currAddr();
729     auto isTB = insn.isInsnType(COND_BR_t::TB_MASK, COND_BR_t::TB);
730     
731     if(labs(disp) > MAX_CBRANCH_OFFSET ||
732             (isTB && labs(disp) > MAX_TBRANCH_OFFSET))
733     {
734         const unsigned char *origInsn = insn.ptr();
735         Address origFrom = gen.currAddr();
736
737         /*
738          * A conditional branch of the form:
739          *    b.cond A
740          * C: ...next insn...:
741          * [Note that b.cond could also be cbz, cbnz, tbz or tbnz -- all valid conditional branch instructions]
742          *
743          * Gets converted to:
744          *    b.cond B
745          *    b      C
746          * B: b      A
747          * C: ...next insn...
748          */
749
750         // Store start index of code buffer to later calculate how much the original instruction's will have moved
751         codeBufIndex_t startIdx = gen.getIndex();
752
753         /* Generate the --b.cond B-- instruction. Directly modifying the offset 
754          * bits of the instruction passed since other bits are to remain the same anyway.
755            B will be 4 bytes from the next instruction. (it will get multiplied by 4 by the CPU) */
756         instruction newInsn(insn);
757         if(insn.isInsnType(COND_BR_t::TB_MASK, COND_BR_t::TB))
758             INSN_SET(newInsn, 5, 18, 0x1);
759         else
760             INSN_SET(newInsn, 5, 23, 0x1);
761         generate(gen, newInsn);
762
763         /* Generate the --b C-- instruction. C will be 4 bytes from the next 
764          * instruction, hence offset for this instruction is set to 1.
765           (it will get multiplied by 4 by the CPU) */
766         newInsn.clear();
767         INSN_SET(newInsn, 0, 25, 0x1);
768         INSN_SET(newInsn, 26, 31, 0x05);
769         generate(gen, newInsn);
770
771         /* Generate the final --b A-- instruction.
772          * The 'from' address to be passed in to generateBranch is now several
773          * bytes (8 actually, but I'm not hardcoding this) ahead of the original 'from' address.
774          * So adjust it accordingly.*/
775         codeBufIndex_t curIdx = gen.getIndex();
776         Address newFrom = origFrom + (unsigned)(curIdx - startIdx);
777         insnCodeGen::generateBranch(gen, newFrom, target);
778     } 
779     else
780     {
781         instruction condBranchInsn(insn);
782
783         // Set the displacement immediate
784         if(isTB)
785             INSN_SET(condBranchInsn, 5, 18, disp >> 2);
786         else
787             INSN_SET(condBranchInsn, 5, 23, disp >> 2);
788
789         generate(gen, condBranchInsn);
790     }
791
792     return true;
793 }
794
795 bool insnCodeGen::modifyCall(Address target,
796                              NS_aarch64::instruction &insn,
797                              codeGen &gen) {
798     if (insn.isUncondBranch())
799         return modifyJump(target, insn, gen);
800     else
801         return modifyJcc(target, insn, gen);
802 }
803
804 bool insnCodeGen::modifyData(Address target,
805         NS_aarch64::instruction &insn,
806         codeGen &gen) 
807 {
808     int raw = insn.asInt();
809     bool isneg = false;
810
811     if (target < gen.currAddr())
812         isneg = true;
813
814     if (((raw >> 24) & 0x1F) == 0x10) {
815         Address offset;
816         if((raw >> 31) & 0x1) {
817             target &= 0xFFFFF000;
818             Address cur = gen.currAddr() & 0xFFFFF000;
819             offset = isneg ? (cur - target) : (target - cur);
820             offset >>= 12;
821         } else {
822             Address cur = gen.currAddr();
823             offset = isneg ? (cur - target) : (target - cur);
824         }
825         signed long imm = isneg ? -((signed long)offset) : offset;
826
827         //If offset is within +/- 1 MB, modify the instruction (ADR/ADRP) with the new offset
828         if (offset <= (1 << 20)) {
829             instruction newInsn(insn);
830             INSN_SET(newInsn, 5, 23, ((imm >> 2) & 0x7FFFF));
831             INSN_SET(newInsn, 29, 30, (imm & 0x3));
832             generate(gen, newInsn);
833         }
834         //Else, generate move instructions to move the value to the same register
835         else {
836             //Register rd = raw & 0x1F;
837             //loadImmIntoReg<Address>(gen, rd, target);
838             instruction newInsn;
839             instruction newInsn2;
840             newInsn.clear();
841             signed long page_rel = ((long)(target >> 12)) - ((long)(gen.currAddr() >> 12));
842             signed long off = target & 0xFFFF;
843             INSN_SET(newInsn, 0, 4, raw & 0x1F);
844             INSN_SET(newInsn, 5, 23, ((page_rel >> 2) & 0x7FFFF));
845             INSN_SET(newInsn, 24, 28, 0x10);
846             INSN_SET(newInsn, 29, 30, (page_rel & 0x3));
847             INSN_SET(newInsn, 31, 31, 1);
848             generate(gen, newInsn);
849             newInsn2.clear();
850             INSN_SET(newInsn2, 0, 4, raw & 0x1F);
851             INSN_SET(newInsn2, 5, 9, raw & 0x1F);
852             INSN_SET(newInsn2, 10, 21, off);
853             INSN_SET(newInsn2, 22, 31, 0x244);
854             generate(gen , newInsn2);
855
856         }
857     } else if (((raw >> 24) & 0x3F) == 0x18 || ((raw >> 24) & 0x3F) == 0x1C) {
858         Address offset = !isneg ? (target - gen.currAddr()) : (gen.currAddr() - target);
859         //If offset is within +/- 1 MB, modify the instruction (LDR/LDRSW) with the new offset
860         if (offset <= (1 << 20)) {
861             instruction newInsn(insn);
862
863             isneg ? (offset += 4) : (offset -= 4);
864             signed long imm = isneg ? -(offset >> 2) : (offset >> 2);
865             INSN_SET(newInsn, 5, 23, (imm & 0x7FFFF));
866
867             generate(gen, newInsn);
868         }
869         //Else, generate move instructions to move the value to the same register
870         else {
871             //Get scratch register for loading the target address in
872             Register immReg = gen.rs()->getScratchRegister(gen, true);
873             if(immReg == REG_NULL)
874                 assert(!"No scratch register available to load the target address into for a PC-relative data access using LDR/LDRSW!");
875             //Generate sequence of instructions for loading the target address in scratch register
876             assert(!"DDDD");
877             loadImmIntoReg<Address>(gen, immReg, target);
878
879             Register rt = raw & 0x1F;
880
881             //Generate instruction for reading value at target address using unsigned-offset variant of the immediate variant of LDR/LDRSW
882             instruction newInsn;
883             newInsn.clear();
884
885             if(((raw >> 31) & 0x1) == 0) {
886                 INSN_SET(newInsn, 30, 30, ((raw >> 30) & 0x1));
887                 INSN_SET(newInsn, 22, 29, LDRImmUIOp);
888             } else {
889                 INSN_SET(newInsn, 22, 29, LDRSWImmUIOp);
890             }
891
892             INSN_SET(newInsn, 31, 31, 0x1);
893             INSN_SET(newInsn, 10, 21, 0);
894             INSN_SET(newInsn, 5, 9, immReg);
895             INSN_SET(newInsn, 0, 4, rt);
896
897             generate(gen, newInsn);
898         }
899     } else {
900         assert(!"Got an instruction other than ADR/ADRP/LDR(literal)/LDRSW(literal) in PC-relative data access!");
901     }
902
903     return true;
904 }
905