ARM: Fix register allocation for ldrd-optimized HREFK.
[luajit-2.0.git] / src / buildvm_asm.c
blobf975eadc7815abb522fabbe650c394f3b9f2f177
1 /*
2 ** LuaJIT VM builder: Assembler source code emitter.
3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4 */
6 #include "buildvm.h"
7 #include "lj_bc.h"
9 /* ------------------------------------------------------------------------ */
11 #if LJ_TARGET_X86ORX64
12 /* Emit bytes piecewise as assembler text. */
13 static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
15 int i;
16 for (i = 0; i < n; i++) {
17 if ((i & 15) == 0)
18 fprintf(ctx->fp, "\t.byte %d", p[i]);
19 else
20 fprintf(ctx->fp, ",%d", p[i]);
21 if ((i & 15) == 15) putc('\n', ctx->fp);
23 if ((n & 15) != 0) putc('\n', ctx->fp);
26 /* Emit relocation */
27 static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
29 switch (ctx->mode) {
30 case BUILD_elfasm:
31 if (type)
32 fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
33 else
34 fprintf(ctx->fp, "\t.long %s\n", sym);
35 break;
36 case BUILD_coffasm:
37 fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
38 if (type)
39 fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
40 else
41 fprintf(ctx->fp, "\t.long %s\n", sym);
42 break;
43 default: /* BUILD_machasm for relative relocations handled below. */
44 fprintf(ctx->fp, "\t.long %s\n", sym);
45 break;
49 static const char *const jccnames[] = {
50 "jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
51 "js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
54 /* Emit relocation for the incredibly stupid OSX assembler. */
55 static void emit_asm_reloc_mach(BuildCtx *ctx, uint8_t *cp, int n,
56 const char *sym)
58 const char *opname = NULL;
59 if (--n < 0) goto err;
60 if (cp[n] == 0xe8) {
61 opname = "call";
62 } else if (cp[n] == 0xe9) {
63 opname = "jmp";
64 } else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
65 opname = jccnames[cp[n]-0x80];
66 n--;
67 } else {
68 err:
69 fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
70 sym);
71 exit(1);
73 emit_asm_bytes(ctx, cp, n);
74 fprintf(ctx->fp, "\t%s %s\n", opname, sym);
76 #else
77 /* Emit words piecewise as assembler text. */
78 static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
80 int i;
81 for (i = 0; i < n; i += 4) {
82 if ((i & 15) == 0)
83 fprintf(ctx->fp, "\t.long 0x%08x", *(uint32_t *)(p+i));
84 else
85 fprintf(ctx->fp, ",0x%08x", *(uint32_t *)(p+i));
86 if ((i & 15) == 12) putc('\n', ctx->fp);
88 if ((n & 15) != 0) putc('\n', ctx->fp);
91 /* Emit relocation as part of an instruction. */
92 static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
93 const char *sym)
95 uint32_t ins;
96 emit_asm_words(ctx, p, n-4);
97 ins = *(uint32_t *)(p+n-4);
98 #if LJ_TARGET_ARM
99 if ((ins & 0xff000000u) == 0xfa000000u) {
100 fprintf(ctx->fp, "\tblx %s\n", sym);
101 } else if ((ins & 0x0e000000u) == 0x0a000000u) {
102 fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
103 "eqnecsccmiplvsvchilsgeltgtle" + 2*(ins >> 28), sym);
104 } else {
105 fprintf(stderr,
106 "Error: unsupported opcode %08x for %s symbol relocation.\n",
107 ins, sym);
108 exit(1);
110 #elif LJ_TARGET_PPC || LJ_TARGET_PPCSPE
111 if ((ins >> 26) == 16) {
112 fprintf(ctx->fp, "\t%s %d, %d, %s\n",
113 (ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
114 } else if ((ins >> 26) == 18) {
115 fprintf(ctx->fp, "\t%s %s\n", (ins & 1) ? "bl" : "b", sym);
116 } else {
117 fprintf(stderr,
118 "Error: unsupported opcode %08x for %s symbol relocation.\n",
119 ins, sym);
120 exit(1);
122 #elif LJ_TARGET_MIPS
123 fprintf(stderr,
124 "Error: unsupported opcode %08x for %s symbol relocation.\n",
125 ins, sym);
126 exit(1);
127 #else
128 #error "missing relocation support for this architecture"
129 #endif
131 #endif
133 #if LJ_TARGET_ARM
134 #define ELFASM_PX "%%"
135 #else
136 #define ELFASM_PX "@"
137 #endif
139 /* Emit an assembler label. */
140 static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
142 switch (ctx->mode) {
143 case BUILD_elfasm:
144 fprintf(ctx->fp,
145 "\n\t.globl %s\n"
146 "\t.hidden %s\n"
147 "\t.type %s, " ELFASM_PX "%s\n"
148 "\t.size %s, %d\n"
149 "%s:\n",
150 name, name, name, isfunc ? "function" : "object", name, size, name);
151 break;
152 case BUILD_coffasm:
153 fprintf(ctx->fp, "\n\t.globl %s\n", name);
154 if (isfunc)
155 fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
156 fprintf(ctx->fp, "%s:\n", name);
157 break;
158 case BUILD_machasm:
159 fprintf(ctx->fp,
160 "\n\t.private_extern %s\n"
161 "%s:\n", name, name);
162 break;
163 default:
164 break;
168 /* Emit alignment. */
169 static void emit_asm_align(BuildCtx *ctx, int bits)
171 switch (ctx->mode) {
172 case BUILD_elfasm:
173 case BUILD_coffasm:
174 fprintf(ctx->fp, "\t.p2align %d\n", bits);
175 break;
176 case BUILD_machasm:
177 fprintf(ctx->fp, "\t.align %d\n", bits);
178 break;
179 default:
180 break;
184 /* ------------------------------------------------------------------------ */
186 /* Emit assembler source code. */
187 void emit_asm(BuildCtx *ctx)
189 int i, rel;
191 fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
192 fprintf(ctx->fp, "\t.text\n");
193 emit_asm_align(ctx, 4);
195 emit_asm_label(ctx, ctx->beginsym, 0, 0);
196 if (ctx->mode != BUILD_machasm)
197 fprintf(ctx->fp, ".Lbegin:\n");
199 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
200 /* This should really be moved into buildvm_arm.dasc. */
201 fprintf(ctx->fp,
202 ".fnstart\n"
203 ".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
204 ".pad #28\n");
205 #endif
206 #if LJ_TARGET_MIPS
207 fprintf(ctx->fp, ".set nomips16\n.abicalls\n.set noreorder\n.set nomacro\n");
208 #endif
210 for (i = rel = 0; i < ctx->nsym; i++) {
211 int32_t ofs = ctx->sym[i].ofs;
212 int32_t next = ctx->sym[i+1].ofs;
213 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND) && \
214 LJ_HASFFI
215 if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
216 fprintf(ctx->fp,
217 ".globl lj_err_unwind_arm\n"
218 ".personality lj_err_unwind_arm\n"
219 ".fnend\n"
220 ".fnstart\n"
221 ".save {r4, r5, r11, lr}\n"
222 ".setfp r11, sp\n");
223 #endif
224 emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
225 while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
226 BuildReloc *r = &ctx->reloc[rel];
227 int n = r->ofs - ofs;
228 #if LJ_TARGET_X86ORX64
229 if (ctx->mode == BUILD_machasm && r->type != 0) {
230 emit_asm_reloc_mach(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
231 } else {
232 emit_asm_bytes(ctx, ctx->code+ofs, n);
233 emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
235 ofs += n+4;
236 #else
237 emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
238 ofs += n;
239 #endif
240 rel++;
242 #if LJ_TARGET_X86ORX64
243 emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
244 #else
245 emit_asm_words(ctx, ctx->code+ofs, next-ofs);
246 #endif
249 #if LJ_TARGET_ARM && defined(__GNUC__) && !defined(LUAJIT_NO_UNWIND)
250 fprintf(ctx->fp,
251 #if !LJ_HASFFI
252 ".globl lj_err_unwind_arm\n"
253 ".personality lj_err_unwind_arm\n"
254 #endif
255 ".fnend\n");
256 #endif
258 fprintf(ctx->fp, "\n");
259 switch (ctx->mode) {
260 case BUILD_elfasm:
261 fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
262 #if LJ_TARGET_PPCSPE
263 /* Soft-float ABI + SPE. */
264 fprintf(ctx->fp, "\t.gnu_attribute 4, 2\n\t.gnu_attribute 8, 3\n");
265 #elif LJ_TARGET_PPC
266 /* Hard-float ABI. */
267 fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
268 #endif
269 /* fallthrough */
270 case BUILD_coffasm:
271 fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
272 break;
273 case BUILD_machasm:
274 fprintf(ctx->fp,
275 "\t.cstring\n"
276 "\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
277 break;
278 default:
279 break;
281 fprintf(ctx->fp, "\n");