cheaper mul by small constants on amd64
[qbe.git] / emit.c
blobba0174b0bbd1e1025e4f693beb90eb76db32d8f4
1 #include "all.h"
3 enum {
4 SecText,
5 SecData,
6 SecBss,
7 };
9 void
10 emitlnk(char *n, Lnk *l, int s, FILE *f)
12 static char *sec[2][3] = {
13 [0][SecText] = ".text",
14 [0][SecData] = ".data",
15 [0][SecBss] = ".bss",
16 [1][SecText] = ".abort \"unreachable\"",
17 [1][SecData] = ".section .tdata,\"awT\"",
18 [1][SecBss] = ".section .tbss,\"awT\"",
20 char *pfx, *sfx;
22 pfx = n[0] == '"' ? "" : T.assym;
23 sfx = "";
24 if (T.apple && l->thread) {
25 l->sec = "__DATA";
26 l->secf = "__thread_data,thread_local_regular";
27 sfx = "$tlv$init";
28 fputs(
29 ".section __DATA,__thread_vars,"
30 "thread_local_variables\n",
33 fprintf(f, "%s%s:\n", pfx, n);
34 fprintf(f,
35 "\t.quad __tlv_bootstrap\n"
36 "\t.quad 0\n"
37 "\t.quad %s%s%s\n\n",
38 pfx, n, sfx
41 if (l->sec) {
42 fprintf(f, ".section %s", l->sec);
43 if (l->secf)
44 fprintf(f, ",%s", l->secf);
45 } else
46 fputs(sec[l->thread != 0][s], f);
47 fputc('\n', f);
48 if (l->align)
49 fprintf(f, ".balign %d\n", l->align);
50 if (l->export)
51 fprintf(f, ".globl %s%s\n", pfx, n);
52 fprintf(f, "%s%s%s:\n", pfx, n, sfx);
55 void
56 emitfnlnk(char *n, Lnk *l, FILE *f)
58 emitlnk(n, l, SecText, f);
61 void
62 emitdat(Dat *d, FILE *f)
64 static char *dtoa[] = {
65 [DB] = "\t.byte",
66 [DH] = "\t.short",
67 [DW] = "\t.int",
68 [DL] = "\t.quad"
70 static int64_t zero;
71 char *p;
73 switch (d->type) {
74 case DStart:
75 zero = 0;
76 break;
77 case DEnd:
78 if (d->lnk->common) {
79 if (zero == -1)
80 die("invalid common data definition");
81 p = d->name[0] == '"' ? "" : T.assym;
82 fprintf(f, ".comm %s%s,%"PRId64,
83 p, d->name, zero);
84 if (d->lnk->align)
85 fprintf(f, ",%d", d->lnk->align);
86 fputc('\n', f);
88 else if (zero != -1) {
89 emitlnk(d->name, d->lnk, SecBss, f);
90 fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
92 break;
93 case DZ:
94 if (zero != -1)
95 zero += d->u.num;
96 else
97 fprintf(f, "\t.fill %"PRId64",1,0\n", d->u.num);
98 break;
99 default:
100 if (zero != -1) {
101 emitlnk(d->name, d->lnk, SecData, f);
102 if (zero > 0)
103 fprintf(f, "\t.fill %"PRId64",1,0\n", zero);
104 zero = -1;
106 if (d->isstr) {
107 if (d->type != DB)
108 err("strings only supported for 'b' currently");
109 fprintf(f, "\t.ascii %s\n", d->u.str);
111 else if (d->isref) {
112 p = d->u.ref.name[0] == '"' ? "" : T.assym;
113 fprintf(f, "%s %s%s%+"PRId64"\n",
114 dtoa[d->type], p, d->u.ref.name,
115 d->u.ref.off);
117 else {
118 fprintf(f, "%s %"PRId64"\n",
119 dtoa[d->type], d->u.num);
121 break;
125 typedef struct Asmbits Asmbits;
127 struct Asmbits {
128 char bits[16];
129 int size;
130 Asmbits *link;
133 static Asmbits *stash;
136 stashbits(void *bits, int size)
138 Asmbits **pb, *b;
139 int i;
141 assert(size == 4 || size == 8 || size == 16);
142 for (pb=&stash, i=0; (b=*pb); pb=&b->link, i++)
143 if (size <= b->size)
144 if (memcmp(bits, b->bits, size) == 0)
145 return i;
146 b = emalloc(sizeof *b);
147 memcpy(b->bits, bits, size);
148 b->size = size;
149 b->link = 0;
150 *pb = b;
151 return i;
154 static void
155 emitfin(FILE *f, char *sec[3])
157 Asmbits *b;
158 char *p;
159 int lg, i;
160 double d;
162 if (!stash)
163 return;
164 fprintf(f, "/* floating point constants */\n");
165 for (lg=4; lg>=2; lg--)
166 for (b=stash, i=0; b; b=b->link, i++) {
167 if (b->size == (1<<lg)) {
168 fprintf(f,
169 ".section %s\n"
170 ".p2align %d\n"
171 "%sfp%d:",
172 sec[lg-2], lg, T.asloc, i
174 for (p=b->bits; p<&b->bits[b->size]; p+=4)
175 fprintf(f, "\n\t.int %"PRId32,
176 *(int32_t *)p);
177 if (lg <= 3) {
178 if (lg == 2)
179 d = *(float *)b->bits;
180 else
181 d = *(double *)b->bits;
182 fprintf(f, " /* %f */\n\n", d);
183 } else
184 fprintf(f, "\n\n");
187 while ((b=stash)) {
188 stash = b->link;
189 free(b);
193 void
194 elf_emitfin(FILE *f)
196 static char *sec[3] = { ".rodata", ".rodata", ".rodata" };
198 emitfin(f ,sec);
199 fprintf(f, ".section .note.GNU-stack,\"\",@progbits\n");
202 void
203 elf_emitfnfin(char *fn, FILE *f)
205 fprintf(f, ".type %s, @function\n", fn);
206 fprintf(f, ".size %s, .-%s\n", fn, fn);
209 void
210 macho_emitfin(FILE *f)
212 static char *sec[3] = {
213 "__TEXT,__literal4,4byte_literals",
214 "__TEXT,__literal8,8byte_literals",
215 ".abort \"unreachable\"",
218 emitfin(f, sec);
221 static uint32_t *file;
222 static uint nfile;
223 static uint curfile;
225 void
226 emitdbgfile(char *fn, FILE *f)
228 uint32_t id;
229 uint n;
231 id = intern(fn);
232 for (n=0; n<nfile; n++)
233 if (file[n] == id) {
234 /* gas requires positive
235 * file numbers */
236 curfile = n + 1;
237 return;
239 if (!file)
240 file = vnew(0, sizeof *file, PHeap);
241 vgrow(&file, ++nfile);
242 file[nfile-1] = id;
243 curfile = nfile;
244 fprintf(f, ".file %u %s\n", curfile, fn);
247 void
248 emitdbgloc(uint line, uint col, FILE *f)
250 if (col != 0)
251 fprintf(f, "\t.loc %u %u %u\n", curfile, line, col);
252 else
253 fprintf(f, "\t.loc %u %u\n", curfile, line);