x86: use push instruction for saving registers
[neatcc.git] / arm.c
blobbb29f0dcb94dc21ed3577e592a3594e6645cb391
1 /* architecture-dependent code generation for ARM */
2 #include <stdlib.h>
3 #include <string.h>
4 #include "ncc.h"
6 #define MIN(a, b) ((a) < (b) ? (a) : (b))
7 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
8 #define oi4(i) oi((i), 4)
10 #define REG_DP 10 /* data pointer register */
11 #define REG_TMP 12 /* temporary register */
12 #define REG_LR 14 /* link register */
13 #define REG_PC 15 /* program counter */
14 #define REG_RET 0 /* returned value register */
16 #define I_AND 0x00
17 #define I_EOR 0x01
18 #define I_SUB 0x02
19 #define I_RSB 0x03
20 #define I_ADD 0x04
21 #define I_TST 0x08
22 #define I_CMP 0x0a
23 #define I_ORR 0x0c
24 #define I_MOV 0x0d
25 #define I_MVN 0x0f
27 int tmpregs[] = {4, 5, 6, 7, 8, 9, 3, 2, 1, 0};
28 int argregs[] = {0, 1, 2, 3};
30 static struct mem cs; /* generated code */
32 /* code generation functions */
33 static char *ointbuf(long n, int l)
35 static char buf[16];
36 int i;
37 for (i = 0; i < l; i++) {
38 buf[i] = n & 0xff;
39 n >>= 8;
41 return buf;
44 static void oi(long n, int l)
46 mem_put(&cs, ointbuf(n, l), l);
49 static void oi_at(long pos, long n, int l)
51 mem_cpy(&cs, pos, ointbuf(n, l), l);
54 static long opos(void)
56 return mem_len(&cs);
59 /* compiled division functions; div.s contains the source */
60 static int udivdi3[] = {
61 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
62 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
63 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
64 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
65 0xe1a00003, 0xe1a0f00e,
67 static int umoddi3[] = {
68 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
70 static int divdi3[] = {
71 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
72 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
73 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
74 0xe8bd8030,
76 static int moddi3[] = {
77 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
80 static long *rel_sym; /* relocation symbols */
81 static long *rel_flg; /* relocation flags */
82 static long *rel_off; /* relocation offsets */
83 static long rel_n, rel_sz; /* relocation count */
85 static long lab_sz; /* label count */
86 static long *lab_loc; /* label offsets in cs */
87 static long jmp_n, jmp_sz; /* jump count */
88 static long *jmp_off; /* jump offsets */
89 static long *jmp_dst; /* jump destinations */
90 static long jmp_ret; /* the position of the last return jmp */
92 static void lab_add(long id)
94 while (id >= lab_sz) {
95 int lab_n = lab_sz;
96 lab_sz = MAX(128, lab_sz * 2);
97 lab_loc = mextend(lab_loc, lab_n, lab_sz, sizeof(*lab_loc));
99 lab_loc[id] = opos();
102 static void jmp_add(long off, long dst)
104 if (jmp_n == jmp_sz) {
105 jmp_sz = MAX(128, jmp_sz * 2);
106 jmp_off = mextend(jmp_off, jmp_n, jmp_sz, sizeof(*jmp_off));
107 jmp_dst = mextend(jmp_dst, jmp_n, jmp_sz, sizeof(*jmp_dst));
109 jmp_off[jmp_n] = off;
110 jmp_dst[jmp_n] = dst;
111 jmp_n++;
114 void i_label(long id)
116 lab_add(id + 1);
119 static void rel_add(long sym, long flg, long off)
121 if (rel_n == rel_sz) {
122 rel_sz = MAX(128, rel_sz * 2);
123 rel_sym = mextend(rel_sym, rel_n, rel_sz, sizeof(*rel_sym));
124 rel_flg = mextend(rel_flg, rel_n, rel_sz, sizeof(*rel_flg));
125 rel_off = mextend(rel_off, rel_n, rel_sz, sizeof(*rel_off));
127 rel_sym[rel_n] = sym;
128 rel_flg[rel_n] = flg;
129 rel_off[rel_n] = off;
130 rel_n++;
133 static int putdiv = 0; /* output div/mod functions */
134 static int func_call; /* */
136 static void i_call(long sym, long off);
138 static void i_div(char *func)
140 putdiv = 1;
141 func_call = 1;
142 i_call(out_sym(func), 0);
145 /* data pool */
146 static long *num_off; /* data immediate value */
147 static long *num_sym; /* relocation data symbol name */
148 static int num_n, num_sz;
150 static int pool_find(long sym, long off)
152 int i;
153 for (i = 0; i < num_n; i++)
154 if (sym == num_sym[i] && off == num_off[i])
155 return i << 2;
156 if (num_n == num_sz) {
157 num_sz = MAX(128, num_sz * 2);
158 num_off = mextend(num_off, num_n, num_sz, sizeof(*num_off));
159 num_sym = mextend(num_sym, num_n, num_sz, sizeof(*num_sym));
161 num_off[i] = off;
162 num_sym[i] = sym;
163 return (num_n++) << 2;
166 static int pool_num(long num)
168 return pool_find(-1, num);
171 static int pool_reloc(long sym, long off)
173 return pool_find(sym, off);
176 static void pool_write(void)
178 int i;
179 for (i = 0; i < num_n; i++) {
180 if (num_sym[i] >= 0)
181 rel_add(num_sym[i], OUT_CS, opos());
182 oi4(num_off[i]);
187 * data processing:
188 * +---------------------------------------+
189 * |COND|00|I| op |S| Rn | Rd | operand2 |
190 * +---------------------------------------+
192 * S: set condition code
193 * Rn: first operand
194 * Rd: destination operand
196 * I=0 operand2=| shift | Rm |
197 * I=1 operand2=|rota| imm |
199 #define ADD(op, rd, rn, s, i, cond) \
200 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
201 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
203 static int add_encimm(unsigned n)
205 int i = 0;
206 while (i < 12 && (n >> ((4 + i) << 1)))
207 i++;
208 return (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);
211 static unsigned add_decimm(int n)
213 int rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;
214 return (n & 0xff) << (rot << 1);
217 static int add_rndimm(unsigned n)
219 int rot = (n >> 8) & 0x0f;
220 int num = n & 0xff;
221 if (rot == 0)
222 return n;
223 if (num == 0xff) {
224 num = 0;
225 rot = (rot + 12) & 0x0f;
227 return ((num + 1) & 0xff) | (rot << 8);
230 static int opcode_add(int op)
232 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
233 static int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};
234 return rx[op & 0x0f];
237 static void i_add(int op, int rd, int rn, int rm)
239 oi4(ADD(opcode_add(op), rd, rn, 0, 0, 14) | rm);
242 static void i_add_imm(int op, int rd, int rn, long n)
244 oi4(ADD(opcode_add(op), rd, rn, 0, 1, 14) | add_encimm(n));
247 static void i_ldr(int l, int rd, int rn, int off, int bt);
249 static void i_num(int rd, long n)
251 int enc = add_encimm(n);
252 if (n == add_decimm(enc)) {
253 oi4(ADD(I_MOV, rd, 0, 0, 1, 14) | enc);
254 return;
256 enc = add_encimm(-n - 1);
257 if (~n == add_decimm(enc)) {
258 oi4(ADD(I_MVN, rd, 0, 0, 1, 14) | enc);
259 return;
261 i_ldr(1, rd, REG_DP, pool_num(n), LONGSZ);
264 static void i_add_anyimm(int rd, int rn, long n)
266 int neg = n < 0;
267 int imm = add_encimm(neg ? -n : n);
268 if (imm == add_decimm(neg ? -n : n)) {
269 oi4(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);
270 } else {
271 i_num(rd, n);
272 i_add(O_ADD, rd, rd, rn);
277 * multiply
278 * +----------------------------------------+
279 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
280 * +----------------------------------------+
282 * Rd: destination
283 * A: accumulate
284 * C: set condition codes
286 * I=0 operand2=| shift | Rm |
287 * I=1 operand2=|rota| imm |
289 #define MUL(rd, rn, rs) \
290 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
292 static void i_mul(int rd, int rn, int rm)
294 oi4(MUL(rd, rn, rm));
297 static int opcode_set(long op)
299 /* lt, ge, eq, ne, le, gt */
300 static int ucond[] = {3, 2, 0, 1, 9, 8};
301 static int scond[] = {11, 10, 0, 1, 13, 12};
302 long bt = O_T(op);
303 return bt & T_MSIGN ? scond[op & 0x0f] : ucond[op & 0x0f];
306 static void i_tst(int rn, int rm)
308 oi4(ADD(I_TST, 0, rn, 1, 0, 14) | rm);
311 static void i_cmp(int rn, int rm)
313 oi4(ADD(I_CMP, 0, rn, 1, 0, 14) | rm);
316 static void i_cmp_imm(int rn, long n)
318 oi4(ADD(I_CMP, 0, rn, 1, 1, 14) | add_encimm(n));
321 static void i_set(int cond, int rd)
323 oi4(ADD(I_MOV, rd, 0, 0, 1, 14));
324 oi4(ADD(I_MOV, rd, 0, 0, 1, opcode_set(cond)) | 1);
327 #define SM_LSL 0
328 #define SM_LSR 1
329 #define SM_ASR 2
331 static int opcode_shl(long op)
333 if (op & 0x0f)
334 return O_T(op) & T_MSIGN ? SM_ASR : SM_LSR;
335 return SM_LSL;
338 static void i_shl(long op, int rd, int rm, int rs)
340 int sm = opcode_shl(op);
341 oi4(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);
344 static void i_shl_imm(long op, int rd, int rn, long n)
346 int sm = opcode_shl(op);
347 oi4(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rn);
350 void i_mov(int rd, int rn)
352 oi4(ADD(I_MOV, rd, 0, 0, 0, 14) | rn);
356 * single data transfer:
357 * +------------------------------------------+
358 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
359 * +------------------------------------------+
361 * I: immediate/offset
362 * P: post/pre indexing
363 * U: down/up
364 * B: byte/word
365 * W: writeback
366 * L: store/load
367 * Rn: base register
368 * Rd: source/destination register
370 * I=0 offset=| immediate |
371 * I=1 offset=| shift | Rm |
373 * halfword and signed data transfer
374 * +----------------------------------------------+
375 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
376 * +----------------------------------------------+
378 * +----------------------------------------------+
379 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
380 * +----------------------------------------------+
382 * S: singed
383 * H: halfword
385 #define LDR(l, rd, rn, b, u, p, w) \
386 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
387 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
388 #define LDRH(l, rd, rn, s, h, u, i) \
389 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
390 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
392 static void i_ldr(int l, int rd, int rn, int off, int bt)
394 int b = T_SZ(bt) == 1;
395 int h = T_SZ(bt) == 2;
396 int s = l && (bt & T_MSIGN);
397 int half = h || (b && s);
398 int maximm = half ? 0x100 : 0x1000;
399 int neg = off < 0;
400 if (neg)
401 off = -off;
402 while (off >= maximm) {
403 int imm = add_encimm(off);
404 oi4(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);
405 rn = REG_TMP;
406 off -= add_decimm(imm);
408 if (!half)
409 oi4(LDR(l, rd, rn, b, !neg, 1, 0) | off);
410 else
411 oi4(LDRH(l, rd, rn, s, h, !neg, 1) |
412 ((off & 0xf0) << 4) | (off & 0x0f));
415 static void i_sym(int rd, long sym, long off)
417 int doff = pool_reloc(sym, off);
418 i_ldr(1, rd, REG_DP, doff, LONGSZ);
421 static void i_neg(int rd, int r1)
423 oi4(ADD(I_RSB, rd, r1, 0, 1, 14));
426 static void i_not(int rd, int r1)
428 oi4(ADD(I_MVN, rd, 0, 0, 0, 14) | r1);
431 static void i_lnot(int rd, int r1)
433 i_tst(r1, r1);
434 i_set(O_EQ, rd);
437 /* rd = rd & ((1 << bits) - 1) */
438 static void i_zx(int rd, int r1, int bits)
440 if (bits <= 8) {
441 oi4(ADD(I_AND, rd, r1, 0, 1, 14) | add_encimm((1 << bits) - 1));
442 } else {
443 i_shl_imm(O_SHL, rd, r1, 32 - bits);
444 i_shl_imm(O_SHR, rd, rd, 32 - bits);
448 static void i_sx(int rd, int r1, int bits)
450 i_shl_imm(O_SHL, rd, r1, 32 - bits);
451 i_shl_imm(O_MK(O_SHR, SLNG), rd, rd, 32 - bits);
455 * branch:
456 * +-----------------------------------+
457 * |COND|101|L| offset |
458 * +-----------------------------------+
460 * L: link
462 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
463 ((((o) - 8) >> 2) & 0x00ffffff))
464 static long i_jmp(long op, long rn, long rm)
466 long pos;
467 if (O_C(op) == O_JMP) {
468 pos = opos();
469 oi4(BL(14, 0, 0));
470 return pos;
472 if (O_C(op) & O_JZ) {
473 i_tst(rn, rn);
474 pos = opos();
475 oi4(BL(O_C(op) == O_JZ ? 0 : 1, 0, 0));
476 return pos;
478 if (O_C(op) & O_JCC) {
479 if (op & O_NUM)
480 i_cmp_imm(rn, rm);
481 else
482 i_cmp(rn, rm);
483 pos = opos();
484 oi4(BL(opcode_set(op), 0, 0));
485 return pos;
487 return -1;
490 static void i_memcpy(int rd, int rs, int rn)
492 oi4(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
493 oi4(BL(4, 0, 16));
494 oi4(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);
495 oi4(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);
496 oi4(BL(14, 0, -16));
499 static void i_memset(int rd, int rs, int rn)
501 oi4(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
502 oi4(BL(4, 0, 12));
503 oi4(LDR(0, rs, rd, 1, 1, 0, 0) | 1);
504 oi4(BL(14, 0, -12));
507 static void i_call_reg(int rd)
509 i_mov(REG_LR, REG_PC);
510 i_mov(REG_PC, rd);
513 static void i_call(long sym, long off)
515 rel_add(sym, OUT_CS | OUT_RLREL | OUT_RL24, opos());
516 oi4(BL(14, 1, off));
519 int i_imm(long lim, long n)
521 return add_decimm(add_encimm(n)) == n;
524 long i_reg(long op, long *rd, long *r1, long *r2, long *r3, long *tmp)
526 long oc = O_C(op);
527 *rd = 0;
528 *r1 = 0;
529 *r2 = 0;
530 *r3 = 0;
531 *tmp = 0;
532 if (oc & O_MOV) {
533 *rd = R_TMPS;
534 *r1 = oc & (O_NUM | O_SYM) ? LONGSZ * 8 : R_TMPS;
535 return 0;
537 if (oc & O_MUL && oc & (O_NUM | O_SYM))
538 return 1;
539 if (oc == O_DIV || oc == O_MOD) {
540 *rd = 1 << REG_RET;
541 *r1 = 1 << argregs[0];
542 *r2 = 1 << argregs[1];
543 *tmp = R_TMPS & ~R_PERM;
544 return 0;
546 if (oc & O_BOP) {
547 *rd = R_TMPS;
548 *r1 = R_TMPS;
549 *r2 = op & O_NUM ? 0 : R_TMPS;
550 return 0;
552 if (oc & O_UOP) {
553 *rd = R_TMPS;
554 *r1 = op & O_NUM ? 0 : R_TMPS;
555 return 0;
557 if (oc == O_MSET || oc == O_MCPY) {
558 *r1 = 1 << 4;
559 *r2 = 1 << 5;
560 *r3 = 1 << 6;
561 *tmp = (1 << 4) | (1 << 6) | (oc == O_MCPY ? (1 << 5) : 0);
562 return 0;
564 if (oc == O_RET) {
565 *r1 = (1 << REG_RET);
566 return 0;
568 if (oc & O_CALL) {
569 *rd = (1 << REG_RET);
570 *r1 = oc & O_SYM ? 0 : R_TMPS;
571 *tmp = R_TMPS & ~R_PERM;
572 return 0;
574 if (oc & O_LD) {
575 *rd = R_TMPS;
576 *r1 = R_TMPS;
577 *r2 = oc & O_NUM ? 0 : R_TMPS;
578 return 0;
580 if (oc & O_ST) {
581 *r1 = R_TMPS;
582 *r2 = R_TMPS;
583 *r3 = oc & O_NUM ? 0 : R_TMPS;
584 return 0;
586 if (oc & O_JZ) {
587 *r1 = R_TMPS;
588 return 0;
590 if (oc & O_JCC) {
591 *r1 = R_TMPS;
592 *r2 = oc & O_NUM ? 0 : R_TMPS;
593 return 0;
595 if (oc == O_JMP)
596 return 0;
597 return 1;
600 long i_ins(long op, long rd, long r1, long r2, long r3)
602 long oc = O_C(op);
603 long bt = O_T(op);
604 if (op & O_ADD) {
605 if (op & O_NUM) {
606 if (i_imm(0, r2))
607 i_add_imm(op, rd, r1, r2);
608 else
609 i_add_anyimm(rd, r1, r2);
610 } else {
611 i_add(op, rd, r1, r2);
614 if (op & O_SHL) {
615 if (op & O_NUM)
616 i_shl_imm(op, rd, r1, r2);
617 else
618 i_shl(op, rd, r1, r2);
620 if (op & O_MUL) {
621 if (oc == O_MUL)
622 i_mul(rd, r1, r2);
623 if (oc == O_DIV)
624 i_div(O_T(op) & T_MSIGN ? "__divdi3" : "__udivdi3");
625 if (oc == O_MOD)
626 i_div(O_T(op) & T_MSIGN ? "__moddi3" : "__umoddi3");
627 return 0;
629 if (oc & O_CMP) {
630 if (op & O_NUM)
631 i_cmp_imm(r1, r2);
632 else
633 i_cmp(r1, r2);
634 i_set(op, rd);
635 return 0;
637 if (oc & O_UOP) {
638 if (oc == O_NEG)
639 i_neg(rd, r1);
640 if (oc == O_NOT)
641 i_not(rd, r1);
642 if (oc == O_LNOT)
643 i_lnot(rd, r1);
644 return 0;
646 if (oc == O_CALL) {
647 func_call = 1;
648 i_call_reg(r1);
649 return 0;
651 if (oc == (O_CALL | O_SYM)) {
652 func_call = 1;
653 i_call(r1, r2);
654 return 0;
656 if (oc == (O_MOV | O_SYM)) {
657 i_sym(rd, r1, r2);
658 return 0;
660 if (oc == (O_MOV | O_NUM)) {
661 i_num(rd, r1);
662 return 0;
664 if (oc == O_MSET) {
665 i_memset(r1, r2, r3);
666 return 0;
668 if (oc == O_MCPY) {
669 i_memcpy(r1, r2, r3);
670 return 0;
672 if (oc == O_RET) {
673 jmp_ret = opos();
674 jmp_add(i_jmp(O_JMP, 0, 0), 0);
675 return 0;
677 if (oc == (O_LD | O_NUM)) {
678 i_ldr(1, rd, r1, r2, bt);
679 return 0;
681 if (oc == (O_ST | O_NUM)) {
682 i_ldr(0, r1, r2, r3, bt);
683 return 0;
685 if (oc == O_MOV) {
686 if (T_SZ(bt) == LONGSZ)
687 i_mov(rd, r1);
688 else {
689 if (bt & T_MSIGN)
690 i_sx(rd, r1, T_SZ(bt) * 8);
691 else
692 i_zx(rd, r1, T_SZ(bt) * 8);
694 return 0;
696 if (oc & O_JXX) {
697 jmp_add(i_jmp(op, r1, r2), r3 + 1);
698 return 0;
700 return 1;
703 void i_wrap(int argc, long sargs, long spsub, int initfp, long sregs, long sregs_pos)
705 long body_n;
706 void *body;
707 long diff; /* prologue length */
708 long dpadd;
709 int nsargs = 0; /* number of saved arguments */
710 int initdp = num_n > 0; /* initialize data pointer */
711 long pregs = 1; /* registers saved in function prologue */
712 int i;
713 if (func_call)
714 initfp = 1;
715 if (!initfp && !spsub && !initdp && !sargs && argc < N_ARGS)
716 pregs = 0;
717 initfp = initfp || pregs;
718 /* removing the last jmp to the epilogue */
719 if (jmp_ret + 4 == opos()) {
720 mem_cut(&cs, jmp_ret);
721 jmp_n--;
723 lab_add(0); /* the return label */
724 body_n = mem_len(&cs);
725 body = mem_get(&cs);
726 /* generating function prologue */
727 for (i = 0; i < N_ARGS; i++)
728 if ((1 << argregs[i]) & sargs)
729 nsargs++;
730 if (nsargs & 0x1) { /* keeping stack 8-aligned */
731 for (i = 0; i < N_ARGS; i++)
732 if (!((1 << argregs[i]) & sargs))
733 break;
734 sargs |= 1 << argregs[i];
736 if (sargs)
737 oi4(0xe92d0000 | sargs); /* stmfd sp!, {r0-r3} */
738 if (pregs) {
739 oi4(0xe1a0c00d); /* mov r12, sp */
740 oi4(0xe92d5c00); /* stmfd sp!, {sl, fp, ip, lr} */
742 if (initfp)
743 oi4(0xe1a0b00d); /* mov fp, sp */
744 if (sregs) { /* sregs_pos should be encoded as immediate */
745 int npos = add_decimm(add_rndimm(add_encimm(-sregs_pos)));
746 spsub += npos + sregs_pos;
747 sregs_pos = -npos;
749 if (spsub) { /* sub sp, sp, xx */
750 spsub = ALIGN(spsub, 8);
751 spsub = add_decimm(add_rndimm(add_encimm(spsub)));
752 oi4(0xe24dd000 | add_encimm(spsub));
754 if (initdp) {
755 dpadd = opos();
756 oi4(0xe28fa000); /* add dp, pc, xx */
758 if (sregs) { /* saving registers */
759 oi4(0xe24bc000 | add_encimm(-sregs_pos));
760 oi4(0xe88c0000 | sregs); /* stmea ip, {r4-r9} */
762 diff = mem_len(&cs);
763 mem_put(&cs, body, body_n);
764 free(body);
765 /* generating function epilogue */
766 if (sregs) { /* restoring saved registers */
767 oi4(0xe24bc000 | add_encimm(-sregs_pos));
768 oi4(0xe89c0000 | sregs); /* ldmfd ip, {r4-r9} */
770 if (pregs) {
771 oi4(0xe89bac00); /* ldmfd fp, {sl, fp, sp, pc} */
772 } else {
773 oi4(0xe1a0f00e); /* mov pc, lr */
775 /* adjusting code offsets */
776 for (i = 0; i < rel_n; i++)
777 rel_off[i] += diff;
778 for (i = 0; i < jmp_n; i++)
779 jmp_off[i] += diff;
780 for (i = 0; i < lab_sz; i++)
781 lab_loc[i] += diff;
782 /* writing the data pool */
783 if (initdp) {
784 int dpoff = opos() - dpadd - 8;
785 dpoff = add_decimm(add_rndimm(add_encimm(dpoff)));
786 mem_putz(&cs, dpadd + dpoff + 8 - opos());
787 /* fill data ptr addition: dp = pc + xx */
788 oi_at(dpadd, 0xe28fa000 | add_encimm(dpoff), 4);
790 pool_write();
793 static void i_fill(long src, long dst)
795 long *d = mem_buf(&cs) + src;
796 long c = (*d & 0xff000000) | (((dst - src - 8) >> 2) & 0x00ffffff);
797 oi_at(src, c, 4);
800 void i_code(char **c, long *c_len, long **rsym, long **rflg, long **roff, long *rcnt)
802 int i;
803 for (i = 0; i < jmp_n; i++) /* filling jmp destinations */
804 i_fill(jmp_off[i], lab_loc[jmp_dst[i]]);
805 *c_len = mem_len(&cs);
806 *c = mem_get(&cs);
807 *rsym = rel_sym;
808 *rflg = rel_flg;
809 *roff = rel_off;
810 *rcnt = rel_n;
811 rel_sym = NULL;
812 rel_flg = NULL;
813 rel_off = NULL;
814 rel_n = 0;
815 rel_sz = 0;
816 jmp_n = 0;
817 num_n = 0;
818 func_call = 0;
821 void i_done(void)
823 if (putdiv) {
824 o_code("__udivdi3", (void *) udivdi3, sizeof(udivdi3));
825 o_code("__umoddi3", (void *) umoddi3, sizeof(umoddi3));
826 o_code("__divdi3", (void *) divdi3, sizeof(divdi3));
827 o_code("__moddi3", (void *) moddi3, sizeof(moddi3));
829 free(jmp_off);
830 free(jmp_dst);
831 free(lab_loc);
832 free(num_sym);
833 free(num_off);