12 #define LOC_LOCAL 0x10
16 #define REG_PC 15 /* program counter */
17 #define REG_LR 14 /* link register */
18 #define REG_SP 13 /* stack pointer */
19 #define REG_TMP 12 /* temporary register */
20 #define REG_FP 11 /* frame pointer register */
21 #define REG_DP 10 /* data pointer register */
22 #define REG_RET 0 /* returned value register */
23 #define REG_FORK 0 /* result of conditional branches */
25 #define MIN(a, b) ((a) < (b) ? (a) : (b))
26 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
29 static char cs
[SECSIZE
]; /* code segment */
31 static char ds
[SECSIZE
]; /* data segment */
33 static long bsslen
; /* bss segment size */
39 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
44 long off
; /* offset from a symbol or a local */
45 unsigned loc
; /* variable location */
46 unsigned bt
; /* type of address; zero when not a pointer */
52 /* arch-specific functions */
53 static void i_ldr(int l
, int rd
, int rn
, int off
, int bt
);
54 static void i_mov(int rd
, int rn
);
55 static void i_add(int op
, int rd
, int rn
, int rm
);
56 static void i_shl(int op
, int rd
, int rm
, int rs
);
57 static void i_mul(int rd
, int rn
, int rm
);
58 static void i_cmp(int rn
, int rm
);
59 static int i_decodeable(long imm
);
60 static void i_add_imm(int op
, int rd
, int rn
, long n
);
61 static void i_shl_imm(int op
, int rd
, int rn
, long n
);
62 static void i_cmp_imm(int rn
, long n
);
63 static void i_add_anyimm(int rd
, int rn
, long n
);
64 static void i_num(int rd
, long n
);
65 static void i_sym(int rd
, char *sym
, int off
);
66 static void i_set(int op
, int rd
);
67 static void i_neg(int rd
);
68 static void i_not(int rd
);
69 static void i_lnot(int rd
);
70 static void i_zx(int rd
, int bits
);
71 static void i_sx(int rd
, int bits
);
72 static void i_b(void);
73 static void i_bz(int rn
, int z
);
74 static void i_b_fill(long src
, long dst
);
75 static void i_memcpy(int rd
, int rs
, int rn
);
76 static void i_memset(int rd
, int rs
, int rn
);
77 static void i_call(char *sym
, int off
);
78 static void i_call_reg(int rd
);
79 static void i_prolog(void);
80 static void i_epilog(void);
82 static struct tmp
*regs
[NREGS
];
83 static int tmpregs
[] = {4, 5, 6, 7, 8, 9, 0, 1, 2, 3};
84 static int argregs
[] = {0, 1, 2, 3};
87 #define MAXJMPS (1 << 14)
89 static long labels
[MAXJMPS
];
91 static long jmp_loc
[MAXJMPS
];
92 static int jmp_goal
[MAXJMPS
];
102 static void jmp_add(int id
)
104 if (njmps
>= MAXJMPS
)
105 err("nomem: MAXJMPS reached!\n");
106 jmp_loc
[njmps
] = cslen
- 4;
107 jmp_goal
[njmps
] = id
;
111 static void jmp_fill(void)
114 for (i
= 0; i
< njmps
; i
++)
115 i_b_fill(jmp_loc
[i
], labels
[jmp_goal
[i
]]);
118 /* output div/mod functions */
119 static int putdiv
= 0;
121 /* generating code */
123 static void os(void *s
, int n
)
125 memcpy(cs
+ cslen
, s
, n
);
129 static void oi(long n
)
131 *(int *) (cs
+ cslen
) = n
;
135 static long sp_push(int size
)
143 static void tmp_mem(struct tmp
*tmp
)
146 if (!(tmp
->loc
== LOC_REG
))
150 tmp
->addr
= -sp_push(LONGSZ
);
151 i_ldr(0, src
, REG_FP
, tmp
->addr
, LONGSZ
);
156 static void num_cast(struct tmp
*t
, unsigned bt
)
158 if (!(bt
& BT_SIGNED
) && BT_SZ(bt
) != LONGSZ
)
159 t
->addr
&= ((1l << (long) (BT_SZ(bt
) * 8)) - 1);
160 if (bt
& BT_SIGNED
&& BT_SZ(bt
) != LONGSZ
&&
161 t
->addr
> (1l << (BT_SZ(bt
) * 8 - 1)))
162 t
->addr
= -((1l << (BT_SZ(bt
) * 8)) - t
->addr
);
165 static void tmp_reg(struct tmp
*tmp
, int dst
, int deref
)
172 if (tmp
->loc
== LOC_NUM
) {
173 i_num(dst
, tmp
->addr
);
178 if (tmp
->loc
== LOC_SYM
) {
179 i_sym(dst
, tmp
->sym
, tmp
->off
);
184 if (tmp
->loc
== LOC_REG
) {
186 i_ldr(1, dst
, tmp
->addr
, 0, bt
);
187 else if (dst
!= tmp
->addr
)
188 i_mov(dst
, tmp
->addr
);
189 regs
[tmp
->addr
] = NULL
;
191 if (tmp
->loc
== LOC_LOCAL
) {
193 i_ldr(1, dst
, REG_FP
, tmp
->addr
+ tmp
->off
, bt
);
195 i_add_anyimm(dst
, REG_FP
, tmp
->addr
+ tmp
->off
);
197 if (tmp
->loc
== LOC_MEM
) {
198 i_ldr(1, dst
, REG_FP
, tmp
->addr
, LONGSZ
);
200 i_ldr(1, dst
, dst
, 0, bt
);
207 static void reg_free(int reg
)
212 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
213 if (!regs
[tmpregs
[i
]]) {
214 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
220 static void reg_for(int reg
, struct tmp
*t
)
222 if (regs
[reg
] && regs
[reg
] != t
)
226 static void tmp_mv(struct tmp
*t
, int reg
)
232 static void tmp_to(struct tmp
*t
, int reg
)
238 static void tmp_drop(int n
)
241 for (i
= ntmp
- n
; i
< ntmp
; i
++)
242 if (tmps
[i
].loc
== LOC_REG
)
243 regs
[tmps
[i
].addr
] = NULL
;
247 static void tmp_pop(int reg
)
249 struct tmp
*t
= TMP(0);
254 static struct tmp
*tmp_new(void)
256 return &tmps
[ntmp
++];
259 static void tmp_push(int reg
)
261 struct tmp
*t
= tmp_new();
268 void o_local(long addr
)
270 struct tmp
*t
= tmp_new();
279 struct tmp
*t
= tmp_new();
285 void o_sym(char *name
)
287 struct tmp
*t
= tmp_new();
288 strcpy(t
->sym
, name
);
294 void o_tmpdrop(int n
)
296 if (n
== -1 || n
> ntmp
)
306 /* make sure tmps remain intact after a conditional expression */
310 for (i
= 0; i
< ntmp
- 1; i
++)
314 void o_forkpush(void)
319 void o_forkjoin(void)
326 struct tmp
*t1
= TMP(0);
327 struct tmp
*t2
= TMP(1);
329 memcpy(&t
, t1
, sizeof(t
));
330 memcpy(t1
, t2
, sizeof(t
));
331 memcpy(t2
, &t
, sizeof(t
));
332 if (t1
->loc
== LOC_REG
)
334 if (t2
->loc
== LOC_REG
)
338 static int reg_get(int mask
)
341 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
342 if ((1 << tmpregs
[i
]) & mask
&& !regs
[tmpregs
[i
]])
344 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
345 if ((1 << tmpregs
[i
]) & mask
) {
346 reg_free(tmpregs
[i
]);
352 static int reg_fortmp(struct tmp
*t
, int notmask
)
354 if (t
->loc
== LOC_REG
&& !(notmask
& (1 << t
->addr
)))
356 return reg_get(~notmask
);
359 static void tmp_copy(struct tmp
*t1
)
361 struct tmp
*t2
= tmp_new();
362 memcpy(t2
, t1
, sizeof(*t1
));
363 if (!(t1
->loc
& (LOC_REG
| LOC_MEM
)))
365 if (t1
->loc
== LOC_MEM
) {
366 tmp_mv(t2
, reg_get(~0));
367 } else if (t1
->loc
== LOC_REG
) {
368 t2
->addr
= reg_fortmp(t2
, 1 << t1
->addr
);
369 i_mov(t2
->addr
, t1
->addr
);
379 void o_cast(unsigned bt
)
381 struct tmp
*t
= TMP(0);
382 if (!t
->bt
&& t
->loc
== LOC_NUM
) {
386 if (BT_SZ(bt
) != LONGSZ
) {
387 int reg
= reg_fortmp(t
, 0);
390 i_sx(reg
, BT_SZ(bt
) * 8);
392 i_zx(reg
, BT_SZ(bt
) * 8);
396 void o_func_beg(char *name
, int argc
, int global
, int vararg
)
398 out_sym(name
, (global
? OUT_GLOB
: 0) | OUT_CS
, cslen
, 0);
406 memset(regs
, 0, sizeof(regs
));
409 void o_deref(unsigned bt
)
411 struct tmp
*t
= TMP(0);
413 tmp_to(t
, reg_fortmp(t
, 0));
419 struct tmp
*t
= TMP(0);
420 tmp_to(t
, reg_fortmp(t
, 0));
423 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
424 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
425 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
427 int o_popnum(long *c
)
429 struct tmp
*t
= TMP(0);
446 void o_func_end(void)
453 long o_mklocal(int size
)
455 return sp_push(ALIGN(size
, LONGSZ
));
458 void o_rmlocal(long addr
, int sz
)
463 long o_arg2loc(int i
)
465 return -(10 + i
) << 2;
468 void o_assign(unsigned bt
)
470 struct tmp
*t1
= TMP(0);
471 struct tmp
*t2
= TMP(1);
472 int r1
= reg_fortmp(t1
, 0);
473 int r2
= reg_fortmp(t2
, 1 << r1
);
478 if (t2
->loc
== LOC_LOCAL
) {
480 off
= t2
->addr
+ t2
->off
;
485 i_ldr(0, r1
, r2
, off
, bt
);
489 static long cu(int op
, long i
)
502 static int c_uop(int op
)
504 struct tmp
*t1
= TMP(0);
508 o_num(cu(op
, t1
->addr
));
512 static long cb(int op
, long a
, long b
)
537 return (unsigned long) a
>> b
;
554 static int c_bop(int op
)
556 struct tmp
*t1
= TMP(0);
557 struct tmp
*t2
= TMP(1);
558 int locals
= LOCAL_PTR(t1
) + LOCAL_PTR(t2
);
559 int syms
= SYM_PTR(t1
) + SYM_PTR(t2
);
560 int nums
= TMP_NUM(t1
) + TMP_NUM(t2
);
561 if (syms
+ locals
== 2 || syms
+ nums
+ locals
!= 2)
564 if ((op
& 0xff) != O_ADD
&& ((op
& 0xff) != O_SUB
|| TMP_NUM(t2
)))
567 long o1
= TMP_NUM(t1
) ? t1
->addr
: t1
->off
;
568 long o2
= TMP_NUM(t2
) ? t2
->addr
: t2
->off
;
569 long ret
= cb(op
, o2
, o1
);
575 long ret
= cb(op
, t2
->addr
, t1
->addr
);
584 int r1
= reg_fortmp(TMP(0), 0);
601 static void bin_regs(int *r1
, int *r2
)
603 struct tmp
*t2
= TMP(0);
604 struct tmp
*t1
= TMP(1);
605 *r2
= reg_fortmp(t2
, 0);
607 *r1
= reg_fortmp(t1
, 1 << *r2
);
612 static int bop_imm(int *r1
, long *n
, int swap
)
614 struct tmp
*t1
= TMP(0);
615 struct tmp
*t2
= TMP(1);
616 if (!TMP_NUM(t1
) && (!swap
|| !TMP_NUM(t2
)))
618 *n
= TMP_NUM(t1
) ? t1
->addr
: t2
->addr
;
619 if (!i_decodeable(*n
))
623 *r1
= reg_fortmp(t2
, 0);
629 static void bin_add(int op
)
633 if (!bop_imm(&r1
, &n
, (op
& 0xff) != O_SUB
)) {
634 i_add_imm(op
, r1
, r1
, n
);
637 i_add(op
, r1
, r1
, r2
);
642 static void bin_shx(int op
)
646 if (!bop_imm(&r1
, &n
, 0)) {
647 i_shl_imm(op
, r1
, r1
, n
);
650 i_shl(op
, r1
, r1
, r2
);
655 static int log2a(unsigned long n
)
658 for (i
= 0; i
< LONGSZ
* 8; i
++)
661 if (i
== LONGSZ
* 8 || !(n
>> (i
+ 1)))
666 /* optimized version of mul/div/mod for powers of two */
667 static int mul_2(int op
)
669 struct tmp
*t1
= TMP(0);
670 struct tmp
*t2
= TMP(1);
674 if ((op
& 0xff) == O_MUL
&& t2
->loc
== LOC_NUM
&& !t2
->bt
)
676 if (t1
->loc
!= LOC_NUM
|| t1
->bt
)
682 if ((op
& 0xff) == O_MUL
) {
691 r2
= reg_fortmp(t2
, 0);
693 i_shl_imm(O_SHL
, r2
, r2
, p
);
700 r2
= reg_fortmp(t2
, 0);
702 i_shl_imm((op
& O_SIGNED
) | O_SHR
, r2
, r2
, p
);
712 r2
= reg_fortmp(t2
, 0);
720 static void bin_div(int op
)
722 struct tmp
*t2
= TMP(0);
723 struct tmp
*t1
= TMP(1);
727 if ((op
& 0xff) == O_DIV
)
728 func
= op
& O_SIGNED
? "__divdi3" : "__udivdi3";
730 func
= op
& O_SIGNED
? "__moddi3" : "__umoddi3";
731 for (i
= 0; i
< ARRAY_SIZE(argregs
); i
++)
732 if (regs
[argregs
[i
]] && regs
[argregs
[i
]] - tmps
< ntmp
- 2)
733 tmp_mem(regs
[argregs
[i
]]);
734 tmp_to(t1
, argregs
[0]);
735 tmp_to(t2
, argregs
[1]);
741 static void bin_mul(int op
)
746 if ((op
& 0xff) == O_DIV
|| (op
& 0xff) == O_MOD
) {
755 static void bin_cmp(int op
)
759 if (!bop_imm(&r1
, &n
, (op
& 0xff) == O_EQ
|| (op
& 0xff) == O_NEQ
)) {
773 if ((op
& 0xf0) == 0x00)
775 if ((op
& 0xf0) == 0x10)
777 if ((op
& 0xf0) == 0x20)
779 if ((op
& 0xf0) == 0x30)
783 static void load_regs2(int *r0
, int *r1
, int *r2
)
785 struct tmp
*t0
= TMP(0);
786 struct tmp
*t1
= TMP(1);
787 struct tmp
*t2
= TMP(2);
788 *r0
= reg_fortmp(t0
, 0);
789 *r1
= reg_fortmp(t1
, 1 << *r0
);
790 *r2
= reg_fortmp(t2
, (1 << *r0
) | (1 << *r1
));
799 load_regs2(&rn
, &rs
, &rd
);
800 i_memcpy(rd
, rs
, rn
);
807 load_regs2(&rn
, &rs
, &rd
);
808 i_memset(rd
, rs
, rn
);
812 static void jxz(int id
, int z
)
814 int r
= reg_fortmp(TMP(0), 0);
836 void o_call(int argc
, int rets
)
840 int aregs
= MIN(ARRAY_SIZE(argregs
), argc
);
841 for (i
= 0; i
< ARRAY_SIZE(argregs
); i
++)
842 if (regs
[argregs
[i
]] && regs
[argregs
[i
]] - tmps
< ntmp
- argc
)
843 tmp_mem(regs
[argregs
[i
]]);
845 sp_push(LONGSZ
* (argc
- aregs
));
846 for (i
= argc
- 1; i
>= aregs
; --i
) {
847 int reg
= reg_fortmp(TMP(0), 0);
849 i_ldr(0, reg
, REG_SP
, (i
- aregs
) * LONGSZ
, LONGSZ
);
852 for (i
= aregs
- 1; i
>= 0; --i
)
853 tmp_to(TMP(aregs
- i
- 1), argregs
[i
]);
856 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
857 i_call(t
->sym
, t
->off
);
860 int reg
= t
->loc
== LOC_REG
? t
->addr
: REG_TMP
;
868 void o_mkbss(char *name
, int size
, int global
)
870 out_sym(name
, OUT_BSS
| (global
? OUT_GLOB
: 0), bsslen
, size
);
871 bsslen
+= ALIGN(size
, OUT_ALIGNMENT
);
874 #define MAXDATS (1 << 10)
875 static char dat_names
[MAXDATS
][NAMELEN
];
876 static int dat_offs
[MAXDATS
];
879 void *o_mkdat(char *name
, int size
, int global
)
881 void *addr
= ds
+ dslen
;
884 err("nomem: MAXDATS reached!\n");
885 strcpy(dat_names
[idx
], name
);
886 dat_offs
[idx
] = dslen
;
887 out_sym(name
, OUT_DS
| (global
? OUT_GLOB
: 0), dslen
, size
);
888 dslen
+= ALIGN(size
, OUT_ALIGNMENT
);
892 static int dat_off(char *name
)
895 for (i
= 0; i
< ndats
; i
++)
896 if (!strcmp(name
, dat_names
[i
]))
901 void o_datset(char *name
, int off
, unsigned bt
)
903 struct tmp
*t
= TMP(0);
904 int sym_off
= dat_off(name
) + off
;
905 if (t
->loc
== LOC_NUM
&& !t
->bt
) {
907 memcpy(ds
+ sym_off
, &t
->addr
, BT_SZ(bt
));
909 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
910 out_rel(t
->sym
, OUT_DS
, sym_off
);
911 memcpy(ds
+ sym_off
, &t
->off
, BT_SZ(bt
));
916 /* compiled division functions; div.s contains the source */
917 static int udivdi3
[] = {
918 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
919 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
920 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
921 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
922 0xe1a00003, 0xe1a0f00e,
924 static int umoddi3
[] = {
925 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
927 static int divdi3
[] = {
928 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
929 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
930 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
933 static int moddi3
[] = {
934 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
940 out_sym("__udivdi3", OUT_CS
, cslen
, 0);
941 os(udivdi3
, sizeof(udivdi3
));
942 out_sym("__umoddi3", OUT_CS
, cslen
, 0);
943 os(umoddi3
, sizeof(umoddi3
));
944 out_sym("__divdi3", OUT_CS
, cslen
, 0);
945 os(divdi3
, sizeof(divdi3
));
946 out_sym("__moddi3", OUT_CS
, cslen
, 0);
947 os(moddi3
, sizeof(moddi3
));
949 out_write(fd
, cs
, cslen
, ds
, dslen
);
952 /* ARM arch specific functions */
965 /* for optimizing cmp + bcc */
966 #define OPT_ISCMP() (last_cmp + 12 == cslen && last_set + 4 == cslen)
967 #define OPT_CCOND() (*(unsigned int *) ((void *) cs + last_set) >> 28)
969 static long last_cmp
= -1;
970 static long last_set
= -1;
975 static long num_offs
[MAXNUMS
]; /* data immediate value */
976 static char num_names
[MAXNUMS
][NAMELEN
]; /* relocation data symbol name */
979 static int pool_find(char *name
, int off
)
982 for (i
= 0; i
< nums
; i
++)
983 if (!strcmp(name
, num_names
[i
]) && off
== num_offs
[i
])
988 static int pool_num(long num
)
990 int idx
= pool_find("", num
);
994 num_names
[idx
][0] = '\0';
999 static int pool_reloc(char *name
, long off
)
1001 int idx
= pool_find(name
, off
);
1004 num_offs
[idx
] = off
;
1005 strcpy(num_names
[idx
], name
);
1010 static void pool_write(void)
1013 for (i
= 0; i
< nums
; i
++) {
1015 out_rel(num_names
[i
], OUT_CS
, cslen
);
1022 * +---------------------------------------+
1023 * |COND|00|I| op |S| Rn | Rd | operand2 |
1024 * +---------------------------------------+
1026 * S: set condition code
1028 * Rd: destination operand
1030 * I=0 operand2=| shift | Rm |
1031 * I=1 operand2=|rota| imm |
1033 #define ADD(op, rd, rn, s, i, cond) \
1034 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
1035 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
1037 static int add_encimm(unsigned n
)
1040 while (i
< 12 && (n
>> ((4 + i
) << 1)))
1042 return (n
>> (i
<< 1)) | (((16 - i
) & 0x0f) << 8);
1045 static unsigned add_decimm(int n
)
1047 int rot
= (16 - ((n
>> 8) & 0x0f)) & 0x0f;
1048 return (n
& 0xff) << (rot
<< 1);
1051 static int add_rndimm(unsigned n
)
1053 int rot
= (n
>> 8) & 0x0f;
1059 rot
= (rot
+ 12) & 0x0f;
1061 return ((num
+ 1) & 0xff) | (rot
<< 8);
1064 static int opcode_add(int op
)
1066 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
1067 static int rx
[] = {I_ADD
, I_SUB
, I_AND
, I_ORR
, I_EOR
};
1068 return rx
[op
& 0x0f];
1071 static void i_add(int op
, int rd
, int rn
, int rm
)
1073 oi(ADD(opcode_add(op
), rd
, rn
, 0, 0, 14) | rm
);
1076 static int i_decodeable(long imm
)
1078 return add_decimm(add_encimm(imm
)) == imm
;
1081 static void i_add_imm(int op
, int rd
, int rn
, long n
)
1083 oi(ADD(opcode_add(op
), rd
, rn
, 0, 1, 14) | add_encimm(n
));
1086 static void i_num(int rd
, long n
)
1088 int enc
= add_encimm(n
);
1089 if (n
== add_decimm(enc
)) {
1090 oi(ADD(I_MOV
, rd
, 0, 0, 1, 14) | enc
);
1093 enc
= add_encimm(-n
- 1);
1094 if (~n
== add_decimm(enc
)) {
1095 oi(ADD(I_MVN
, rd
, 0, 0, 1, 14) | enc
);
1098 i_ldr(1, rd
, REG_DP
, pool_num(n
), LONGSZ
);
1101 static void i_add_anyimm(int rd
, int rn
, long n
)
1104 int imm
= add_encimm(neg
? -n
: n
);
1105 if (imm
== add_decimm(neg
? -n
: n
)) {
1106 oi(ADD(neg
? I_SUB
: I_ADD
, rd
, rn
, 0, 1, 14) | imm
);
1109 i_add(O_ADD
, rd
, rd
, rn
);
1115 * +----------------------------------------+
1116 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
1117 * +----------------------------------------+
1121 * C: set condition codes
1123 * I=0 operand2=| shift | Rm |
1124 * I=1 operand2=|rota| imm |
1126 #define MUL(rd, rn, rs) \
1127 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
1129 static void i_mul(int rd
, int rn
, int rm
)
1131 oi(MUL(rd
, rn
, rm
));
1134 static int opcode_set(int op
)
1136 /* lt, gt, le, ge, eq, neq */
1137 static int ucond
[] = {3, 8, 9, 2, 0, 1};
1138 static int scond
[] = {11, 12, 13, 10, 0, 1};
1139 return op
& O_SIGNED
? scond
[op
& 0x0f] : ucond
[op
& 0x0f];
1142 static void i_tst(int rn
, int rm
)
1144 oi(ADD(I_TST
, 0, rn
, 1, 0, 14) | rm
);
1147 static void i_cmp(int rn
, int rm
)
1150 oi(ADD(I_CMP
, 0, rn
, 1, 0, 14) | rm
);
1153 static void i_cmp_imm(int rn
, long n
)
1156 oi(ADD(I_CMP
, 0, rn
, 1, 1, 14) | add_encimm(n
));
1159 static void i_set(int cond
, int rd
)
1161 oi(ADD(I_MOV
, rd
, 0, 0, 1, 14));
1163 oi(ADD(I_MOV
, rd
, 0, 0, 1, opcode_set(cond
)) | 1);
1170 static int opcode_shl(int op
)
1173 return op
& O_SIGNED
? SM_ASR
: SM_LSR
;
1177 static void i_shl(int op
, int rd
, int rm
, int rs
)
1179 int sm
= opcode_shl(op
);
1180 oi(ADD(I_MOV
, rd
, 0, 0, 0, 14) | (rs
<< 8) | (sm
<< 5) | (1 << 4) | rm
);
1183 static void i_shl_imm(int op
, int rd
, int rn
, long n
)
1185 int sm
= opcode_shl(op
);
1186 oi(ADD(I_MOV
, rd
, 0, 0, 0, 14) | (n
<< 7) | (sm
<< 5) | rn
);
1189 static void i_mov(int rd
, int rn
)
1191 oi(ADD(I_MOV
, rd
, 0, 0, 0, 14) | rn
);
1195 * single data transfer:
1196 * +------------------------------------------+
1197 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
1198 * +------------------------------------------+
1200 * I: immediate/offset
1201 * P: post/pre indexing
1207 * Rd: source/destination register
1209 * I=0 offset=| immediate |
1210 * I=1 offset=| shift | Rm |
1212 * halfword and signed data transfer
1213 * +----------------------------------------------+
1214 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
1215 * +----------------------------------------------+
1217 * +----------------------------------------------+
1218 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
1219 * +----------------------------------------------+
1224 #define LDR(l, rd, rn, b, u, p, w) \
1225 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
1226 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
1227 #define LDRH(l, rd, rn, s, h, u, i) \
1228 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
1229 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
1231 static void i_ldr(int l
, int rd
, int rn
, int off
, int bt
)
1233 int b
= BT_SZ(bt
) == 1;
1234 int h
= BT_SZ(bt
) == 2;
1235 int s
= l
&& (bt
& BT_SIGNED
);
1236 int half
= h
|| (b
&& s
);
1237 int maximm
= half
? 0x100 : 0x1000;
1241 while (off
>= maximm
) {
1242 int imm
= add_encimm(off
);
1243 oi(ADD(neg
? I_SUB
: I_ADD
, REG_TMP
, rn
, 0, 1, 14) | imm
);
1245 off
-= add_decimm(imm
);
1248 oi(LDR(l
, rd
, rn
, b
, !neg
, 1, 0) | off
);
1250 oi(LDRH(l
, rd
, rn
, s
, h
, !neg
, 1) |
1251 ((off
& 0xf0) << 4) | (off
& 0x0f));
1254 static void i_sym(int rd
, char *sym
, int off
)
1256 int doff
= pool_reloc(sym
, off
);
1257 i_ldr(1, rd
, REG_DP
, doff
, LONGSZ
);
1260 static void i_neg(int rd
)
1262 oi(ADD(I_RSB
, rd
, rd
, 0, 1, 14));
1265 static void i_not(int rd
)
1267 oi(ADD(I_MVN
, rd
, 0, 0, 0, 14) | rd
);
1270 static int cond_nots
[] = {1, 0, 3, 2, -1, -1, -1, -1, 9, 8, 11, 10, 13, 12, -1};
1272 static void i_lnot(int rd
)
1275 unsigned int *lset
= (void *) cs
+ last_set
;
1276 int cond
= cond_nots
[OPT_CCOND()];
1277 *lset
= (*lset
& 0x0fffffff) | (cond
<< 28);
1284 /* rd = rd & ((1 << bits) - 1) */
1285 static void i_zx(int rd
, int bits
)
1288 oi(ADD(I_AND
, rd
, rd
, 0, 1, 14) | add_encimm((1 << bits
) - 1));
1290 i_shl_imm(O_SHL
, rd
, rd
, 32 - bits
);
1291 i_shl_imm(O_SHR
, rd
, rd
, 32 - bits
);
1295 static void i_sx(int rd
, int bits
)
1297 i_shl_imm(O_SHL
, rd
, rd
, 32 - bits
);
1298 i_shl_imm(O_SIGNED
| O_SHR
, rd
, rd
, 32 - bits
);
1303 * +-----------------------------------+
1304 * |COND|101|L| offset |
1305 * +-----------------------------------+
1309 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
1310 ((((o) - 8) >> 2) & 0x00ffffff))
1312 static void i_b(void)
1317 static void i_bz(int rn
, int z
)
1320 int cond
= OPT_CCOND();
1321 cslen
= last_cmp
+ 4;
1323 oi(BL(z
? cond_nots
[cond
] : cond
, 0, 0));
1327 oi(BL(z
? 0 : 1, 0, 0));
1330 static void i_b_fill(long src
, long dst
)
1332 long diff
= dst
- src
- 8;
1333 long *m
= (long *) (cs
+ src
);
1334 *m
= (*m
& 0xff000000) | ((diff
>> 2) & 0x00ffffff);
1337 static void i_memcpy(int rd
, int rs
, int rn
)
1339 oi(ADD(I_SUB
, rn
, rn
, 1, 1, 14) | 1);
1341 oi(LDR(1, REG_TMP
, rs
, 1, 1, 0, 0) | 1);
1342 oi(LDR(0, REG_TMP
, rd
, 1, 1, 0, 0) | 1);
1346 static void i_memset(int rd
, int rs
, int rn
)
1348 oi(ADD(I_SUB
, rn
, rn
, 1, 1, 14) | 1);
1350 oi(LDR(0, rs
, rd
, 1, 1, 0, 0) | 1);
1354 static void i_call_reg(int rd
)
1356 i_mov(REG_LR
, REG_PC
);
1360 static void i_call(char *sym
, int off
)
1362 out_rel(sym
, OUT_CS
| OUT_REL24
, cslen
);
1366 static void i_prolog(void)
1372 oi(0xe1a0c00d); /* mov r12, sp */
1373 oi(0xe92d000f); /* stmfd sp!, {r0-r3} */
1374 oi(0xe92d5ff0); /* stmfd sp!, {r0-r11, r12, lr} */
1375 oi(0xe1a0b00d); /* mov fp, sp */
1376 oi(0xe24dd000); /* sub sp, sp, xx */
1377 oi(0xe28fa000); /* add dp, pc, xx */
1380 static void i_epilog(void)
1383 oi(0xe89baff0); /* ldmfd fp, {r4-r11, sp, pc} */
1384 dpoff
= add_decimm(add_rndimm(add_encimm(cslen
- func_beg
- 28)));
1385 cslen
= func_beg
+ dpoff
+ 28;
1386 maxsp
= ALIGN(maxsp
, 8);
1387 maxsp
= add_decimm(add_rndimm(add_encimm(maxsp
)));
1388 /* fill stack sub: sp = sp - xx */
1389 *(long *) (cs
+ func_beg
+ 16) |= add_encimm(maxsp
);
1390 /* fill data ptr addition: dp = pc + xx */
1391 *(long *) (cs
+ func_beg
+ 20) |= add_encimm(dpoff
);