1 /*
2 * Copyright (c) 2006 - 2010, Nils R. Weller
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Emit gas code from intermediate amd64 code
28 */
29 #include "amd64_emit_gas.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <ctype.h>
35 #include "scope.h"
36 #include "type.h"
37 #include "decl.h"
38 #include "icode.h"
39 #include "subexpr.h"
40 #include "token.h"
41 #include "functions.h"
42 #include "symlist.h"
43 #include "dwarf.h"
44 #include "cc1_main.h"
45 #include "x86_gen.h"
46 #include "typemap.h"
47 #include "expr.h"
48 #include "x86_emit_gas.h"
49 #include "inlineasm.h"
50 #include "error.h"
51 #include "n_libc.h"
52
53 static FILE *out;
54
55 static int
init(FILE * fd,struct scope * s)56 init(FILE *fd, struct scope *s) {
57 (void) s;
58 out = fd;
59 return 0;
60 }
61
62 static void
63 print_mem_operand(struct vreg *vr, struct token *constant);
64
65 /*
66 * 04/11/08: Export print_mem_operand() for x86 emitter functions
67 * which are shared between x86 and AMD64 and need this
68 */
69 void
amd64_print_mem_operand_gas(struct vreg * vr,struct token * constant)70 amd64_print_mem_operand_gas(struct vreg *vr, struct token *constant) {
71 print_mem_operand(vr, constant);
72 }
73
74 extern int size_to_gaspostfix(size_t size, struct type *type);
75
76 static void
emit_extern_decls(void)77 emit_extern_decls(void) {
78 if (x86_emit_gas.extern_decls != NULL) {
79 x86_emit_gas.extern_decls();
80 }
81 }
82
83 static void
emit_global_extern_decls(struct decl ** d,int ndecls)84 emit_global_extern_decls(struct decl **d, int ndecls) {
85 x86_emit_gas.global_extern_decls(d, ndecls);
86 }
87
88 static void
emit_global_static_decls(struct decl ** d,int ndecls)89 emit_global_static_decls(struct decl **d, int ndecls) {
90 x86_emit_gas.global_static_decls(d, ndecls);
91 }
92
93 static void
emit_static_init_vars(struct decl * list)94 emit_static_init_vars(struct decl *list) {
95 x86_emit_gas.static_init_vars(list);
96 }
97
98 static void
emit_static_uninit_vars(struct decl * list)99 emit_static_uninit_vars(struct decl *list) {
100 x86_emit_gas.static_uninit_vars(list);
101 }
102
103 static void
emit_static_init_thread_vars(struct decl * list)104 emit_static_init_thread_vars(struct decl *list) {
105 x86_emit_gas.static_init_thread_vars(list);
106 }
107
108 static void
emit_static_uninit_thread_vars(struct decl * list)109 emit_static_uninit_thread_vars(struct decl *list) {
110 x86_emit_gas.static_uninit_thread_vars(list);
111 }
112
113 #if 0
114 static void
115 emit_static_decls(void) {
116 x86_emit_gas.static_decls();
117 }
118 #endif
119
120 static void
emit_struct_inits(struct init_with_name * list)121 emit_struct_inits(struct init_with_name *list) {
122 x86_emit_gas.struct_inits(list);
123 }
124
125 static void
emit_strings(struct ty_string * list)126 emit_strings(struct ty_string *list) {
127 x86_emit_gas.strings(list);
128 }
129
130 static void
emit_fp_constants(struct ty_float * list)131 emit_fp_constants(struct ty_float *list) {
132 x86_emit_gas.fp_constants(list);
133 }
134
135 static void
emit_support_buffers(void)136 emit_support_buffers(void) {
137 #if 0 /* 02/21/09: This is now done by the x86 emitter */
138 if (amd64_need_negmask) {
139 x86_emit_gas.setsection(SECTION_INIT);
140 if (sysflag == OS_OSX) {
141 x_fprintf(out, "\t.align 8\n");
142 } else {
143 x_fprintf(out, "\t.align 16\n");
144 }
145 if (amd64_need_negmask & 1) {
146 x_fprintf(out, "_SSE_Negmask:\n");
147 x_fprintf(out, "\t.long 0x80000000\n");
148 if (sysflag == OS_OSX) {
149 x_fprintf(out, "\t.align 8\n");
150 } else {
151 x_fprintf(out, "\t.align 16\n");
152 }
153 }
154 if (amd64_need_negmask & 2) {
155 x_fprintf(out, "_SSE_Negmask_double:\n");
156 x_fprintf(out, "\t.long 0x00000000\n");
157 x_fprintf(out, "\t.long 0x80000000\n");
158 }
159 }
160 if (amd64_need_ulong_float_mask) {
161 x86_emit_gas.setsection(SECTION_INIT);
162 x_fprintf(out, "\t.align 4\n");
163
164 x_fprintf(out, "_Ulong_float_mask:\n");
165 x_fprintf(out, "\t.long 1602224128\n");
166 }
167 #endif
168 x86_emit_gas.support_buffers();
169 }
170
171 static void
emit_comment(const char * fmt,...)172 emit_comment(const char *fmt, ...) {
173 int rc;
174 va_list va;
175
176 va_start(va, fmt);
177 x_fprintf(out, "# ");
178 rc = vfprintf(out, fmt, va);
179 va_end(va);
180 x_fputc('\n', out);
181
182 if (rc == EOF || fflush(out) == EOF) {
183 perror("vfprintf");
184 exit(EXIT_FAILURE);
185 }
186 }
187
188 static void
emit_dwarf2_line(struct token * tok)189 emit_dwarf2_line(struct token *tok) {
190 (void) tok;
191 unimpl();
192 #if 0
193 x_fprintf(out, "\t[loc %d %d 0]\n",
194 tok->fileid, tok->line);
195 #endif
196 }
197
198 static void
emit_dwarf2_files(void)199 emit_dwarf2_files(void) {
200 struct dwarf_in_file *inf;
201
202 x_fprintf(out, "[file \"%s\"]\n",
203 input_file);
204
205 for (inf = dwarf_files; inf != NULL; inf = inf->next) {
206 x_fprintf(out, "[file %d \"%s\"]\n",
207 inf->id, inf->name);
208 }
209 }
210
211 static void
emit_inlineasm(struct inline_asm_stmt * stmt)212 emit_inlineasm(struct inline_asm_stmt *stmt) {
213 x_fprintf(out, "#APP\n");
214 /*
215 * There may be an empty body for statements where only the side
216 * effect is desired;
217 * __asm__("" ::: "memory");
218 */
219 if (stmt->code != NULL) {
220 inline_instr_to_gas(out, stmt->code);
221 }
222 x_fprintf(out, "#NO_APP\n");
223 }
224
225 static void
emit_unimpl(void)226 emit_unimpl(void) {
227 unimpl();
228 }
229
230 static void
emit_empty(void)231 emit_empty(void) {
232 x_fputc('\n', out);
233 }
234
235 static void
emit_label(const char * name,int is_func)236 emit_label(const char *name, int is_func) {
237 if (is_func) {
238 if (sysflag == OS_OSX) {
239 x_fprintf(out, "_%s:\n", name);
240 } else {
241 x_fprintf(out, "%s:\n", name);
242 }
243 } else {
244 x_fprintf(out, ".%s:\n", name);
245 }
246 }
247
248 static void
emit_call(const char * name)249 emit_call(const char *name) {
250 x86_emit_gas.call(name);
251 }
252
253 static void
emit_callindir(struct reg * r)254 emit_callindir(struct reg *r) {
255 x_fprintf(out, "\tcall *%%%s\n", r->name);
256 }
257
258 static void
emit_func_header(struct function * f)259 emit_func_header(struct function *f) {
260 if (sysflag != OS_OSX) {
261 x_fprintf(out, "\t.type %s, @function\n", f->proto->dtype->name);
262 }
263 }
264
265 static void
emit_func_intro(struct function * f)266 emit_func_intro(struct function *f) {
267 (void) f;
268 x_fprintf(out, "\tpush %%rbp\n"); /* XXX */
269 x_fprintf(out, "\tmov %%rsp, %%rbp\n");
270 }
271
272 static void
emit_func_outro(struct function * f)273 emit_func_outro(struct function *f) {
274 char *name = f->proto->dtype->name;
275
276 if (sysflag != OS_OSX) {
277 x_fprintf(out, "\t.size %s, .-%s\n", name, name);
278 }
279 /*x_fprintf(out, "\tret\n");*/
280 }
281
282
283 static void
emit_define(const char * name,const char * fmt,...)284 emit_define(const char *name, const char *fmt, ...) {
285 x86_emit_gas.define(name, fmt);
286 }
287
288 static void
emit_push(struct function * f,struct icode_instr * ii)289 emit_push(struct function *f, struct icode_instr *ii) {
290 struct vreg *vr = ii->src_vreg;
291 struct reg *r = ii->src_pregs?
292 (void *)ii->src_pregs[0]: (void *)NULL;
293 int ch;
294
295 if (IS_VLA(vr->type->flags)) {
296 ch = 'q';
297 } else {
298 if (backend->get_sizeof_type(vr->type, NULL) == 8) {
299 ch = 'q';
300 } else {
301 ch = 'l';
302 }
303 }
304
305 if (ii->src_pregs) {
306 x_fprintf(out, "\tpush %%%s\n", r->name);
307 } else if (vr->var_backed) {
308 struct decl *d = vr->var_backed;
309
310 if (vr->parent != NULL) {
311 /* Structure or union member */
312 struct decl *d2/* = d*/;
313 struct vreg *vr2;
314
315 vr2 = get_parent_struct(vr);
316 d2 = vr2->var_backed;
317 if (vr2->from_ptr) {
318 if (vr->parent->type->code == TY_STRUCT) {
319 x_fprintf(out, "\tpush%c %lu(%%%s)\n",
320 ch,
321 calc_offsets(vr2),
322 vr2->from_ptr->pregs[0]->name);
323 } else {
324 x_fprintf(out, "\tpush%c (%%%s)\n",
325 ch,
326 vr2->from_ptr->pregs[0]->name);
327 }
328 } else if (d2 && d2->stack_addr != NULL) {
329 long soff = 0;
330
331 if (vr->parent->type->code == TY_STRUCT) {
332 soff = calc_offsets(vr2);
333 }
334 x_fprintf(out, "\tpush%c %ld(%%rbp)\n",
335 ch,
336 -d2->stack_addr->offset+soff);
337 } else if (d2 != NULL) {
338 /* Must be static */
339 x_fprintf(out, "\tpush%c %s",
340 ch,
341 d2->dtype->name);
342 if (vr->parent->type->code == TY_STRUCT) {
343 x_fprintf(out, "+%lu",
344 calc_offsets(vr2));
345 }
346 x_fputc('\n', out);
347 } else {
348 unimpl();
349 }
350 } else {
351 if (d->stack_addr != NULL) {
352 /* Stack */
353 x_fprintf(out, "\tpush%c -%ld(%%rbp)\n",
354 ch,
355 d->stack_addr->offset);
356 } else {
357 /* Static or register variable */
358 if (d->dtype->storage == TOK_KEY_REGISTER) {
359 unimpl();
360 } else {
361 x_fprintf(out, "\tpush%c %s\n",
362 ch, d->dtype->name);
363 }
364 }
365 }
366 } else if (vr->from_const) {
367 struct token *t = vr->from_const;
368
369 if (t->type == TOK_STRING_LITERAL) {
370 struct ty_string *s = t->data;
371 x_fprintf(out, "\tpushq $._Str%lu\n", s->count);
372 } else if (IS_INT(t->type)) {
373 /*
374 * There are only forms of ``int'' and ``long''
375 * constants
376 */
377 #if 0
378 if (t->type == TY_INT) {
379 x_fprintf(out, "\tpushl $%d\n",
380 *(int *) t->data);
381 } else {
382 /* UINT */
383 x_fprintf(out, "\tpushl $%u\n",
384 *(unsigned *) t->data);
385 }
386 #endif
387 x_fprintf(out, "\tpushl $");
388 cross_print_value_by_type(out, t->data, t->type, 0);
389 } else if (IS_LONG(t->type) || IS_LLONG(t->type)) {
390 #if 0
391 if (t->type == TY_LONG || t->type == TY_LLONG) {
392 x_fprintf(out, "\tpushq $%ld\n",
393 *(long *) t->data);
394 } else {
395 /* unsigned */
396 x_fprintf(out, "\tpushq $%lu\n",
397 *(unsigned long *) t->data);
398 }
399 #endif
400 x_fprintf(out, "\tpushq $");
401 cross_print_value_by_type(out, t->data, t->type, 0);
402 } else {
403 puts("BUG in NASM emit_push()");
404 exit(EXIT_FAILURE);
405 }
406 } else if (vr->from_ptr) {
407 x_fprintf(out, "\tpush%c (%%%s)\n", /*ascii_type,*/
408 ch,
409 vr->from_ptr->pregs[0]->name);
410 } else {
411 unimpl();
412 }
413
414 f->total_allocated += 4;
415 }
416
417 static void
emit_allocstack(struct function * f,size_t nbytes)418 emit_allocstack(struct function *f, size_t nbytes) {
419 (void) f;
420 x_fprintf(out, "\tsub $%lu, %%rsp\n", (unsigned long)nbytes);
421 }
422
423
424 static void
emit_freestack(struct function * f,size_t * nbytes)425 emit_freestack(struct function *f, size_t *nbytes) {
426 if (nbytes == NULL) {
427 /* Procedure outro */
428 if (f->total_allocated != 0) {
429 x_fprintf(out, "\tadd $%lu, %%rsp\n",
430 (unsigned long)f->total_allocated);
431 }
432 x_fprintf(out, "\tpop %%rbp\n");
433 } else {
434 if (*nbytes != 0) {
435 x_fprintf(out, "\tadd $%lu, %%rsp\n",
436 (unsigned long)*nbytes);
437 f->total_allocated -= *nbytes;
438 }
439 }
440 }
441
442 static void
emit_adj_allocated(struct function * f,int * nbytes)443 emit_adj_allocated(struct function *f, int *nbytes) {
444 f->total_allocated += *nbytes;
445 }
446
447
448 #if 0
449 static void
450 emit_struct_defs(void) {
451 if (x86_emit_gas.struct_defs) {
452 x86_emit_gas.struct_defs();
453 }
454 }
455 #endif
456
457
458 static void
emit_setsection(int value)459 emit_setsection(int value) {
460 static int init;
461
462 x86_emit_gas.setsection(value);
463 if (value == SECTION_INIT) {
464 if ((init & 1) == 0) {
465 x_fprintf(out, "\t.align 16\n");
466 init |= 1;
467 }
468 } else if (value == SECTION_UNINIT) {
469 if ((init & 2) == 0) {
470 x_fprintf(out, "\t.align 16\n");
471 init |= 2;
472 }
473 }
474 }
475
476 static void
emit_alloc(size_t nbytes)477 emit_alloc(size_t nbytes) {
478 unimpl();
479 (void) nbytes;
480 }
481
482
483 static void
print_mem_or_reg(struct reg * r,struct vreg * vr)484 print_mem_or_reg(struct reg *r, struct vreg *vr) {
485 if (vr->on_var) {
486 struct decl *d = vr->var_backed;
487
488 if (d->stack_addr) {
489 x_fprintf(out, "-%ld(%%rbp)",
490 d->stack_addr->offset);
491 } else {
492 x_fprintf(out, "%s", d->dtype->name);
493 }
494 } else {
495 x_fprintf(out, "%%%s", r->name);
496 }
497 }
498
499
500
501 static void
emit_inc(struct icode_instr * ii)502 emit_inc(struct icode_instr *ii) {
503 x86_emit_gas.inc(ii);
504 }
505
506 static void
emit_dec(struct icode_instr * ii)507 emit_dec(struct icode_instr *ii) {
508 x86_emit_gas.dec(ii);
509 }
510
511 static void
emit_load(struct reg * r,struct vreg * vr)512 emit_load(struct reg *r, struct vreg *vr) {
513 char *p;
514
515 if (r->type == REG_FPR) {
516 if (STUPID_X87(r)) {
517 if (!IS_FLOATING(vr->type->code)) {
518 #if ! REMOVE_FLOATBUF
519 p = "fild";
520
521 /*
522 * 04/06/08: Don't use size postfix for fild - fildt
523 * isn't allowed. Why did this issue not come up
524 * earlier?
525 */
526 if (vr->size >= 10) {
527 x_fprintf(out, "\t%s ", p);
528 } else {
529 x_fprintf(out, "\t%s%c ",
530 p, size_to_gaspostfix(vr->size, vr->type));
531 }
532 #else
533 buggypath();
534 #endif
535 } else {
536 p = "fld";
537 x_fprintf(out, "\t%s%c ",
538 p, size_to_gaspostfix(vr->size, vr->type));
539 }
540 } else {
541 /* SSE */
542 if (!IS_FLOATING(vr->type->code)) {
543 p = "cvtsi2ss";
544 } else {
545 if (vr->type->code == TY_FLOAT) {
546 p = "movss";
547 } else {
548 /* Must be double */
549 p = "movsd";
550 }
551 }
552 x_fprintf(out, "\t%s ", p);
553 }
554 } else {
555 if (vr->stack_addr != NULL) {
556 p = "mov";
557 } else if (vr->type
558 && vr->type->tlist != NULL
559 && (vr->type->tlist->type == TN_ARRAY_OF
560 || vr->type->tlist->type == TN_VARARRAY_OF)) {
561 if (vr->from_const == NULL) {
562 p = "lea";
563 } else {
564 p = "mov";
565 }
566 } else {
567 if (r->size == vr->size
568 || vr->size == 8) {
569 /* == 8 for long long, SA for anonymous */
570 p = "mov";
571 } else {
572 if (vr->type == NULL
573 || vr->type->sign == TOK_KEY_UNSIGNED) {
574 /* XXX 32->64bit? ... */
575 p = "movzx";
576 } else {
577 if (r->size == 8 && vr->size == 4) {
578 if (vr->from_const) {
579 p = "mov";
580 } else {
581 p = "movslq";
582 }
583 } else {
584 p = "movsx";
585 }
586 }
587 }
588 }
589 x_fprintf(out, "\t%s ", p);
590 }
591
592 print_mem_operand(vr, NULL);
593 if (r->type != REG_FPR || !STUPID_X87(r)) {
594 x_fprintf(out, ", %%%s\n", r->name);
595 }
596 x_fputc('\n', out);
597 }
598
599 static void
emit_load_addrlabel(struct reg * r,struct icode_instr * ii)600 emit_load_addrlabel(struct reg *r, struct icode_instr *ii) {
601 x_fprintf(out, "\tlea .%s(%%rip), %%%s\n", ii->dat, r->name);
602 }
603
604 static void
emit_comp_goto(struct reg * r)605 emit_comp_goto(struct reg *r) {
606 x_fprintf(out, "\tjmp *%%%s\n", r->name);
607 }
608
609 /*
610 * Takes vreg source arg - not preg - so that it can be either a preg
611 * or immediate (where that makes sense!)
612 */
613 static void
emit_store(struct vreg * dest,struct vreg * src)614 emit_store(struct vreg *dest, struct vreg *src) {
615 char *p = NULL;
616 int floating = 0;
617 int post = 0;
618 int is_movsx = 0;
619
620 if (dest->size) {
621 post = size_to_gaspostfix(dest->size, dest->type);
622 }
623 #if ! REMOVE_FLOATBUF
624 if (dest == &floatbuf) {
625 /*
626 * XXX this is a botch to ignore the problem of the messed
627 * up floatbuf typing for now. This makes code compile, but
628 * not necessarily work right :-)
629 */
630 if (src->pregs[0]->size == 4 && post == 'q') {
631 post = 'l';
632 }
633 }
634 #endif
635
636 if (src->pregs[0] && src->pregs[0]->type == REG_FPR) {
637 if (STUPID_X87(src->pregs[0])) {
638 if (!IS_FLOATING(dest->type->code)) {
639 #if ! REMOVE_FLOATBUF
640 if (dest->size >= 10) {
641 /*
642 * 04/06/08: Use fisttp instead of fistpt
643 * (postfix). Why was this not encountered
644 * earlier?
645 *
646 *
647 */
648 p = "fisttp";
649 post = 0;
650 } else {
651 p = "fistp";
652 }
653 #else
654 buggypath();
655 #endif
656 } else {
657 p = "fstp";
658 }
659 floating = 1;
660 } else {
661 if (!IS_FLOATING(dest->type->code)) {
662 unimpl();
663 } else {
664 if (dest->type->code == TY_FLOAT) {
665 p = "movss";
666 } else {
667 p = "movsd";
668 }
669 }
670 post = 0;
671 floating = 0; /* because SSE is non-x87-like */
672 }
673 } else {
674 if (dest->stack_addr != NULL || dest->from_const != NULL) {
675 p = "mov";
676 } else {
677 if (src->pregs[0] && dest->size < src->pregs[0]->size) {
678 if (src->type == NULL
679 || src->type->sign
680 == TOK_KEY_UNSIGNED) {
681 /* XXX wow this should never be executed? */
682 x_fprintf(out, "\tmov%c ", post?post:' ');
683 x_fprintf(out, "$0, ");
684 print_mem_operand(dest, NULL);
685 p = "mov";
686 } else {
687 if (dest->from_ptr
688 && src->pregs[0]->size == 4) {
689 /*
690 * ``movslq %eax, (%r9)''
691 * doesn't work :S
692 */
693 src->pregs[0] =
694 find_top_reg(
695 src->pregs[0]);
696 x_fprintf(out,
697 "\tmovslq %%%s, %%%s\n",
698 src->pregs[0]->composed_of[0]->name,
699 src->pregs[0]->name);
700 p = "mov";
701 } else {
702 if (src->pregs[0]->size == 4) {
703 p = "movslq";
704 } else {
705 p = "movsx";
706 is_movsx = 1;
707 }
708 }
709 }
710 } else {
711 p = "mov";
712 }
713 }
714 }
715 if (post) {
716 if (post == 'l' && is_movsx) {
717 /* 04/06/08: Kludge to handle long double conversion
718 * nonsense code.. we must get rid of floatbuf. really
719 */
720 #if ! REMOVE_FLOATBUF
721 x_fprintf(out, "\tmov ");
722 #else
723 buggypath();
724 #endif
725 } else {
726 x_fprintf(out, "\t%s%c ", p, post);
727 }
728 } else {
729 x_fprintf(out, "\t%s ", p);
730 }
731 if (floating) {
732 /* Already done - floating stores only ever come from st0 */
733 print_mem_operand(dest, NULL);
734 x_fputc('\n', out);
735 return;
736 }
737 if (src->from_const) {
738 print_mem_operand(src, NULL);
739 } else {
740 /* Must be register */
741 x_fprintf(out, "%%%s, ", src->pregs[0]->name);
742 }
743 print_mem_operand(dest, NULL);
744 x_fputc('\n', out);
745 }
746
747
748 static void
emit_neg(struct reg ** dest,struct icode_instr * src)749 emit_neg(struct reg **dest, struct icode_instr *src) {
750 x86_emit_gas.neg(dest, src);
751 }
752
753
754 /* XXX 64bit */
755 static void
emit_sub(struct reg ** dest,struct icode_instr * src)756 emit_sub(struct reg **dest, struct icode_instr *src) {
757 if (dest[0]->type == REG_FPR) {
758 if (STUPID_X87(dest[0])) {
759 /* 05/27/08: fsubrp instead of fsubp.. See x86 */
760 x_fprintf(out, "\tfsubrp ");
761 } else {
762 x_fprintf(out, "\tsubs%c ",
763 src->src_vreg->type->code == TY_FLOAT? 's': 'd');
764 }
765 } else {
766 if (src->dest_vreg->type->tlist) {
767 /* ptr arit ... sub rax, edx doesn't work */
768 if (src->src_vreg->size == 4) {
769 /* XXX frontend stuff?! */
770 struct reg *r;
771
772 r = find_top_reg(src->src_pregs[0]);
773 if (src->src_vreg->type->sign
774 != TOK_KEY_UNSIGNED) {
775 x_fprintf(out, "\tmovslq %%%s, %%%s\n",
776 src->src_pregs[0]->name,
777 r->name);
778 }
779 x_fprintf(out, "\tsub %%%s, %%%s\n",
780 r->name,
781 dest[0]->name);
782 return;
783 }
784 }
785 x_fprintf(out, "\tsub ");
786 }
787 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
788 x_fprintf(out, ", %%%s\n", dest[0]->name);
789 }
790
791 /* XXX 64bit */
792 static void
emit_add(struct reg ** dest,struct icode_instr * src)793 emit_add(struct reg **dest, struct icode_instr *src) {
794 if (dest[0]->type == REG_FPR) {
795 if (STUPID_X87(dest[0])) {
796 x_fprintf(out, "\tfaddp ");
797 } else {
798 x_fprintf(out, "\tadds%c ",
799 src->src_vreg->type->code == TY_FLOAT? 's': 'd');
800 }
801 } else {
802 if (src->dest_vreg->type->tlist) {
803 /* ptr arit ... add rax, edx doesn't work */
804 if (src->src_vreg->size == 4) {
805 /* XXX frontend stuff?! */
806 struct reg *r;
807
808 r = find_top_reg(src->src_pregs[0]);
809 if (src->src_vreg->type->sign !=
810 TOK_KEY_UNSIGNED) {
811 x_fprintf(out, "\tmovslq %%%s, %%%s\n",
812 src->src_pregs[0]->name,
813 r->name);
814 }
815 x_fprintf(out, "\tadd %%%s, %%%s\n",
816 r->name,
817 dest[0]->name);
818 return;
819 }
820 }
821 x_fprintf(out, "\tadd ");
822 }
823 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
824 x_fprintf(out, ", %%%s\n", dest[0]->name);
825 }
826
827 /* XXX 64bit */
828 static void
emit_div(struct reg ** dest,struct icode_instr * src,int formod)829 emit_div(struct reg **dest, struct icode_instr *src, int formod) {
830 struct type *ty = src->src_vreg->type;
831 int is_x87 = 0;
832
833 (void) dest; (void) formod;
834 if (!IS_FLOATING(ty->code)) {
835 int is_64bit = IS_LONG(ty->code) || IS_LLONG(ty->code);
836
837 if (ty->sign != TOK_KEY_UNSIGNED) {
838 if (is_64bit) {
839 /*
840 * 07/25/08: This was doing zero-extension
841 * instead of sign-extension!
842 */
843 x_fprintf(out, "\tcqto\n");
844 /* x_fprintf(out, "\txor %%rdx, %%rdx\n");*/
845 } else {
846 /* sign-extend eax to edx:eax */
847 x_fprintf(out, "\tcltd\n");
848 }
849 x_fprintf(out, "\tidiv ");
850 } else {
851 if (is_64bit) {
852 x_fprintf(out, "\txor %%rdx, %%rdx\n");
853 } else {
854 x_fprintf(out, "\txor %%edx, %%edx\n");
855 }
856 x_fprintf(out, "\tdiv ");
857 }
858 } else {
859 if (STUPID_X87(src->src_pregs[0])) {
860 /* XXX why is the fxch needed???? */
861 x_fprintf(out, "\tfxch %%st(1)\n");
862 x_fprintf(out, "\tfdivp ");
863 is_x87 = 1;
864 } else {
865 x_fprintf(out, "\tdivs%c %%%s, %%%s\n",
866 ty->code == TY_FLOAT? 's': 'd',
867 src->src_pregs[0]->name,
868 dest[0]->name);
869 return;
870 }
871 }
872 if (is_x87) {
873 print_mem_or_reg(src->dest_pregs[0], src->dest_vreg);
874 } else {
875 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
876 }
877 x_fputc('\n', out);
878 }
879
880
881 /* XXX 64bit ... */
882 static void
emit_mod(struct reg ** dest,struct icode_instr * src)883 emit_mod(struct reg **dest, struct icode_instr *src) {
884 emit_div(dest, src, 1);
885 if (!IS_LLONG(src->dest_vreg->type->code)
886 && !IS_LONG(src->dest_vreg->type->code)) {
887 x_fprintf(out, "\tmov %%edx, %%%s\n", dest[0]->name);
888 } else {
889 x_fprintf(out, "\tmov %%rdx, %%%s\n", dest[0]->name);
890 }
891 }
892
893
894 /* XXX ouch..how does it work with 64bit? */
895 static void
emit_mul(struct reg ** dest,struct icode_instr * src)896 emit_mul(struct reg **dest, struct icode_instr *src) {
897 struct type *ty = src->src_vreg->type;
898
899 (void) dest;
900
901 if (IS_FLOATING(ty->code)) {
902 if (STUPID_X87(dest[0])) {
903 x_fprintf(out, "\tfmulp ");
904 } else {
905 x_fprintf(out, "\tmuls%c ",
906 ty->code == TY_FLOAT? 's': 'd');
907 }
908 } else if (ty->sign == TOK_KEY_UNSIGNED) {
909 x_fprintf(out, "\tmul ");
910 } else {
911 /* signed integer multiplication */
912 /* XXX should use mul for pointer arithmetic :( */
913 x_fprintf(out, "\timul %%%s, %%%s\n",
914 src->src_pregs[0]->name,
915 src->src_pregs[0]->size == 4? "eax": "rax");
916 return;
917 }
918 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
919 if (IS_FLOATING(ty->code)) {
920 x_fprintf(out, ", %%%s", src->dest_pregs[0]->name);
921 }
922 x_fputc('\n', out);
923 }
924
925 /* XXX sal for signed values!!!!! */
926 static void
emit_shl(struct reg ** dest,struct icode_instr * src)927 emit_shl(struct reg **dest, struct icode_instr *src) {
928 x86_emit_gas.shl(dest, src);
929 }
930
931
932 /* XXX sar for signed values !!!!!!!! */
933 static void
emit_shr(struct reg ** dest,struct icode_instr * src)934 emit_shr(struct reg **dest, struct icode_instr *src) {
935 x86_emit_gas.shr(dest, src);
936 }
937
938 static void
emit_or(struct reg ** dest,struct icode_instr * src)939 emit_or(struct reg **dest, struct icode_instr *src) {
940 x86_emit_gas.or(dest, src);
941 }
942
943 static void
emit_and(struct reg ** dest,struct icode_instr * src)944 emit_and(struct reg **dest, struct icode_instr *src) {
945 x86_emit_gas.and(dest, src);
946 }
947
948 static void
emit_xor(struct reg ** dest,struct icode_instr * src)949 emit_xor(struct reg **dest, struct icode_instr *src) {
950 x86_emit_gas.xor(dest, src);
951 }
952
953 static void
emit_not(struct reg ** dest,struct icode_instr * src)954 emit_not(struct reg **dest, struct icode_instr *src) {
955 x86_emit_gas.not(dest, src);
956 }
957
958 static void
emit_ret(struct icode_instr * ii)959 emit_ret(struct icode_instr *ii) {
960 (void) ii;
961
962 x_fprintf(out, "\tret\n"); /* XXX */
963 }
964
965 extern struct icode_instr *last_x87_cmp;
966 extern struct icode_instr *last_sse_cmp;
967
968 /*
969 * XXX compltee bogus code for token.c ...
970 * call n_xmalloc
971 * movl %rax, -40(rbp)
972 * mov $0, %eax
973 * cmp $0, %eax
974 */
975 static void
emit_cmp(struct reg ** dest,struct icode_instr * src)976 emit_cmp(struct reg **dest, struct icode_instr *src) {
977 if (dest[0]->size == 8
978 && src->src_pregs
979 && src->src_pregs[0]->size == 4) {
980 src->src_pregs[0] = find_top_reg(src->src_pregs[0]);
981 } else if (src->src_pregs && src->src_pregs[0]->size == 8
982 && dest[0]->size == 4) {
983 dest[0] = find_top_reg(dest[0]);
984 }
985
986 if (dest[0]->type == REG_FPR) {
987 if (STUPID_X87(dest[0])) {
988 last_x87_cmp = src;
989 } else {
990 last_sse_cmp = src;
991 }
992 return;
993 } else {
994 fprintf(out, "\tcmp ");
995 }
996 if (src->src_pregs == NULL || src->src_vreg == NULL) {
997 x_fprintf(out, "$0");
998 } else {
999 print_mem_or_reg(src->src_pregs[0], src->src_vreg);
1000 }
1001 x_fprintf(out, ", %%%s\n", dest[0]->name);
1002 }
1003
1004 static void
emit_branch(struct icode_instr * ii)1005 emit_branch(struct icode_instr *ii) {
1006 x86_emit_gas.branch(ii);
1007 }
1008
1009 static void
emit_mov(struct copyreg * cr)1010 emit_mov(struct copyreg *cr) {
1011 x86_emit_gas.mov(cr);
1012 }
1013
1014
1015 static void
emit_setreg(struct reg * dest,int * value)1016 emit_setreg(struct reg *dest, int *value) {
1017 x86_emit_gas.setreg(dest, value);
1018 }
1019
1020 static void
emit_xchg(struct reg * r1,struct reg * r2)1021 emit_xchg(struct reg *r1, struct reg *r2) {
1022 x86_emit_gas.xchg(r1, r2);
1023 }
1024
1025
1026 static void
emit_addrof(struct reg * dest,struct vreg * src,struct vreg * structtop)1027 emit_addrof(struct reg *dest, struct vreg *src, struct vreg *structtop) {
1028 x86_emit_gas.addrof(dest, src, structtop);
1029 }
1030
1031
1032 static char *
get_local_sym_representation(const char * name)1033 get_local_sym_representation(const char *name) {
1034 static char buf[1024];
1035 if (picflag) {
1036 sprintf(buf, ".%s@GOTPCREL(%%rip)", name);
1037 } else {
1038 sprintf(buf, "$.%s", name);
1039 }
1040 return buf;
1041 }
1042
1043 static char *
get_function_sym_representation(const char * name)1044 get_function_sym_representation(const char *name) {
1045 static char buf[1024];
1046 if (picflag) {
1047 sprintf(buf, "%s@PLT", name);
1048 } else {
1049 sprintf(buf, "%s", name);
1050 }
1051 return buf;
1052 }
1053
1054
1055 /*
1056 * Copy initializer to automatic variable of aggregate type
1057 */
1058 static void
emit_copyinit(struct decl * d)1059 emit_copyinit(struct decl *d) {
1060 x_fprintf(out, "\tmov $%lu, %%rdx\n",
1061 (unsigned long)backend->get_sizeof_type(d->dtype, 0));
1062 if (sysflag == OS_OSX) {
1063 x_fprintf(out, "\tlea .%s(%%rip), %%rsi\n", d->init_name->name); /* XXX */
1064 } else {
1065 x_fprintf(out, "\tmov %s, %%rsi\n", get_local_sym_representation(d->init_name->name)); /* XXX */
1066 }
1067 x_fprintf(out, "\tlea -%lu(%%rbp), %%rdi\n", d->stack_addr->offset);
1068 if (sysflag == OS_OSX) {
1069 x_fprintf(out, "\tcall _memcpy\n");
1070 } else {
1071 x_fprintf(out, "\tcall %s\n", get_function_sym_representation("memcpy"));
1072 }
1073 }
1074
1075
1076 /*
1077 * Assign one struct to another (may be any of automatic or static or
1078 * addressed thru pointer)
1079 *
1080 * This stuff now copies intrinsically - i.e. doesn't use memcpy() -
1081 * because that way we can guarantee that no registers are trashed.
1082 * This simplifies things like passing structs to functions on the
1083 * stack, but is currently very simplistic and thus not very fast
1084 * for big structs
1085 *
1086 * (Note that the frontend cannot assume that all registers remain
1087 * intact because other backends do still call memcpy())
1088 */
1089 static void
emit_copystruct(struct copystruct * cs)1090 emit_copystruct(struct copystruct *cs) {
1091 struct vreg *stop;
1092 static unsigned long lcount;
1093
1094 x_fprintf(out, "\tpush %%rdx\n");
1095 x_fprintf(out, "\tpush %%rdi\n");
1096 x_fprintf(out, "\tpush %%rsi\n");
1097 x_fprintf(out, "\tpush %%rax\n");
1098 x_fprintf(out, "\tpush %%rcx\n");
1099
1100 /*
1101 * 07/26/12: XXX ugly kludge to ensure that the register saving above
1102 * does not corrupt sp-relative addressing of structs for function
1103 * call arguments
1104 */
1105 x_fprintf(out, "\tadd $40, %%rsp\n");
1106
1107 /* arg 3 = rdx */
1108 #if 0
1109 x_fprintf(out, "\tmov rdx, %lu\n", (unsigned long)cs->src_vreg->size);
1110 #endif
1111 x_fprintf(out, "\tmov $%lu, %%rcx\n", (unsigned long)cs->src_vreg->size);
1112 if (cs->src_from_ptr == NULL) {
1113 if (cs->src_vreg->parent) {
1114 stop = get_parent_struct(cs->src_vreg);
1115 } else {
1116 stop = NULL;
1117 }
1118 /* arg 2 = rsi */
1119 emit_addrof(&amd64_x86_gprs[4], cs->src_vreg, stop);
1120 } else {
1121 if (cs->src_vreg->parent) {
1122 x_fprintf(out, "\tadd $%lu, %%%s\n",
1123 calc_offsets(cs->src_vreg),
1124 /*cs->src_vreg->memberdecl->offset,*/
1125 cs->src_from_ptr->name);
1126 }
1127 /* arg 2 = rsi */
1128 x_fprintf(out, "\tmov %%%s, %%rsi\n", cs->src_from_ptr->name);
1129 }
1130
1131 if (cs->dest_vreg == NULL) {
1132 /* copy to hidden pointer */
1133 emit_load(&amd64_x86_gprs[5], curfunc->hidden_pointer);
1134 } else if (cs->dest_from_ptr == NULL) {
1135 if (cs->dest_vreg->parent) {
1136 stop = get_parent_struct(cs->dest_vreg);
1137 } else {
1138 stop = NULL;
1139 }
1140 /* arg 3 = rdi */
1141 emit_addrof(&amd64_x86_gprs[5], cs->dest_vreg, stop);
1142 } else {
1143 if (cs->dest_vreg->parent) {
1144 x_fprintf(out, "\tadd $%lu, %%%s\n",
1145 calc_offsets(cs->dest_vreg),
1146 /*cs->dest_vreg->memberdecl->offset,*/
1147 cs->dest_from_ptr->name);
1148 }
1149 /* arg 3 = rdi */
1150 x_fprintf(out, "\tmov %%%s, %%rdi\n", cs->dest_from_ptr->name);
1151 }
1152 #if 0
1153 x_fprintf(out, "\tcall memcpy\n");
1154 #endif
1155 x_fprintf(out, "\t.copystruct%lu:\n", lcount);
1156 x_fprintf(out, "\tmov (%%rsi), %%al\n");
1157 x_fprintf(out, "\tmov %%al, (%%rdi)\n");
1158 x_fprintf(out, "\tinc %%rdi\n");
1159 x_fprintf(out, "\tinc %%rsi\n");
1160 x_fprintf(out, "\tloop .copystruct%lu\n", lcount++);
1161
1162 x_fprintf(out, "\tsub $40, %%rsp\n"); /* XXX reverte addressing kludge */
1163
1164 /* 04/06/08: This was missing! */
1165 x_fprintf(out, "\tpop %%rcx\n");
1166 x_fprintf(out, "\tpop %%rax\n");
1167 x_fprintf(out, "\tpop %%rsi\n");
1168 x_fprintf(out, "\tpop %%rdi\n");
1169 x_fprintf(out, "\tpop %%rdx\n");
1170 }
1171
1172 static void
emit_intrinsic_memcpy(struct int_memcpy_data * data)1173 emit_intrinsic_memcpy(struct int_memcpy_data *data) {
1174 x86_emit_gas.intrinsic_memcpy(data);
1175 }
1176
1177 static void
emit_zerostack(struct stack_block * sb,size_t nbytes)1178 emit_zerostack(struct stack_block *sb, size_t nbytes) {
1179 x_fprintf(out, "\tmov $%lu, %%rdx\n",
1180 (unsigned long)nbytes);
1181 x_fprintf(out, "\tmov $0, %%rsi\n");
1182 x_fprintf(out, "\tlea -%lu(%%rbp), %%rdi\n",
1183 (unsigned long)sb->offset);
1184 if (sysflag == OS_OSX) {
1185 x_fprintf(out, "\tcall _memset\n");
1186 } else {
1187 x_fprintf(out, "\tcall memset\n");
1188 }
1189 }
1190
1191 static void
emit_alloca(struct allocadata * ad)1192 emit_alloca(struct allocadata *ad) {
1193 x_fprintf(out, "\tmov %%%s, %%%s\n", ad->size_reg->name,
1194 ad->size_reg->size == 4? "edi": "rdi");
1195 if (sysflag == OS_OSX) {
1196 x_fprintf(out, "\tcall _malloc\n");
1197 } else {
1198 x_fprintf(out, "\tcall malloc\n");
1199 }
1200 if (ad->result_reg != &amd64_x86_gprs[0]) {
1201 x_fprintf(out, "\tmov %%rax, %%%s\n",
1202 ad->result_reg->name);
1203 }
1204 }
1205
1206 static void
emit_dealloca(struct stack_block * sb,struct reg * r)1207 emit_dealloca(struct stack_block *sb, struct reg *r) {
1208 char *regname = r? r->name: "rdi";
1209 x_fprintf(out, "\tmovq -%lu(%%rbp), %%%s\n",
1210 (unsigned long)sb->offset, regname);
1211 if (sysflag == OS_OSX) {
1212 x_fprintf(out, "\tcall _free\n");
1213 } else {
1214 x_fprintf(out, "\tcall free\n");
1215 }
1216 }
1217
1218 static void
emit_alloc_vla(struct stack_block * sb)1219 emit_alloc_vla(struct stack_block *sb) {
1220 x_fprintf(out, "\tmov -%lu(%%rbp), %%rdi\n",
1221 (unsigned long)sb->offset - backend->get_ptr_size());
1222 if (sysflag == OS_OSX) {
1223 x_fprintf(out, "\tcall _malloc\n");
1224 } else {
1225 x_fprintf(out, "\tcall malloc\n");
1226 }
1227 x_fprintf(out, "\tmov %%rax, -%lu(%%rbp)\n",
1228 (unsigned long)sb->offset);
1229 }
1230
1231 static void
emit_dealloc_vla(struct stack_block * sb,struct reg * r)1232 emit_dealloc_vla(struct stack_block *sb, struct reg *r) {
1233 char *regname = r? r->name: "rdi";
1234 x_fprintf(out, "\tmovq -%lu(%%rbp), %%%s\n",
1235 (unsigned long)sb->offset, regname);
1236 if (sysflag == OS_OSX) {
1237 x_fprintf(out, "\tcall _free\n");
1238 } else {
1239 x_fprintf(out, "\tcall free\n");
1240 }
1241 }
1242
1243 static void
emit_put_vla_size(struct vlasizedata * data)1244 emit_put_vla_size(struct vlasizedata *data) {
1245 x_fprintf(out, "\tmovq %%%s, -%lu(%%rbp)\n",
1246 data->size->name,
1247 (unsigned long)data->blockaddr->offset - data->offset);
1248 }
1249
1250 static void
emit_retr_vla_size(struct vlasizedata * data)1251 emit_retr_vla_size(struct vlasizedata *data) {
1252 x_fprintf(out, "\tmovq -%lu(%%rbp), %%%s\n",
1253 (unsigned long)data->blockaddr->offset - data->offset,
1254 data->size->name);
1255 }
1256
1257 static void
emit_load_vla(struct reg * r,struct stack_block * sb)1258 emit_load_vla(struct reg *r, struct stack_block *sb) {
1259 x_fprintf(out, "\tmovq -%lu(%%rbp), %%%s\n",
1260 (unsigned long)sb->offset, r->name);
1261 }
1262
1263 static void
emit_frame_address(struct builtinframeaddressdata * dat)1264 emit_frame_address(struct builtinframeaddressdata *dat) {
1265 x_fprintf(out, "\tmovq %%rbp, %%%s\n",
1266 dat->result_reg->name);
1267 }
1268
1269
1270
1271 static void
emit_save_ret_addr(struct function * f,struct stack_block * sb)1272 emit_save_ret_addr(struct function *f, struct stack_block *sb) {
1273 (void) f;
1274
1275 x_fprintf(out, "\tmov 8(%%rbp), %%rax\n");
1276 x_fprintf(out, "\tmov %%rax, -%lu(%%rbp)\n", sb->offset);
1277 }
1278
1279 static void
emit_check_ret_addr(struct function * f,struct stack_block * saved)1280 emit_check_ret_addr(struct function *f, struct stack_block *saved) {
1281 static unsigned long labval = 0;
1282
1283 (void) f;
1284
1285 x_fprintf(out, "\tmovq -%lu(%%rbp), %%rcx\n", saved->offset);
1286 x_fprintf(out, "\tcmpq 8(%%rbp), %%rcx\n");
1287 x_fprintf(out, "\tje .doret%lu\n", labval);
1288 x_fprintf(out, "\tcall __nwcc_stack_corrupt\n");
1289 x_fprintf(out, ".doret%lu:\n", labval++);
1290 }
1291
1292 static void
do_stack(FILE * out,struct decl * d)1293 do_stack(FILE *out, struct decl *d) {
1294 char *sign;
1295
1296 if (d->stack_addr->is_func_arg) {
1297 sign = "";
1298 } else {
1299 sign = "-";
1300 }
1301 x_fprintf(out, "%s%lu(%%rbp", sign, d->stack_addr->offset);
1302 }
1303
1304 static void
print_mem_operand(struct vreg * vr,struct token * constant)1305 print_mem_operand(struct vreg *vr, struct token *constant) {
1306 int needbracket = 1;
1307
1308 if (vr && vr->from_const != NULL) {
1309 constant = vr->from_const;
1310 }
1311 if (constant != NULL) {
1312 struct token *t = vr->from_const;
1313
1314 if (!IS_FLOATING(t->type)) {
1315 /*
1316 * XXX hmm sometimes we use $.Str and sometimes
1317 * .Str??
1318 */
1319 x_fputc('$', out);
1320 }
1321 /* if (t->type == TY_INT) {
1322 x_fprintf(out, "%d",
1323 *(int *)t->data);
1324 } else if (t->type == TY_UINT) {
1325 x_fprintf(out, "%u",
1326 *(unsigned *)t->data);
1327 } else if (t->type == TY_LONG
1328 || t->type == TY_LLONG) {
1329 x_fprintf(out, "%ld",
1330 *(long *)t->data);
1331 } else if (t->type == TY_ULONG
1332 || t->type == TY_ULLONG) {
1333 x_fprintf(out, "%lu",
1334 *(unsigned long *)t->data);
1335 }*/
1336 if (IS_INT(t->type) || IS_LONG(t->type) || IS_LLONG(t->type)) {
1337 cross_print_value_by_type(out, t->data, t->type, 0);
1338 #if ALLOW_CHAR_SHORT_CONSTANTS
1339 } else if (IS_CHAR(t->type) || IS_SHORT(t->type)) {
1340 cross_print_value_by_type(out, t->data, t->type, 0);
1341 #endif
1342 } else if (t->type == TOK_STRING_LITERAL) {
1343 struct ty_string *ts = t->data;
1344 x_fprintf(out, "._Str%ld",
1345 ts->count);
1346 } else if (t->type == TY_FLOAT
1347 || t->type == TY_DOUBLE
1348 || t->type == TY_LDOUBLE) {
1349 struct ty_float *tf = t->data;
1350
1351 x_fprintf(out, "(_Float%lu)",
1352 tf->count);
1353 } else {
1354 printf("loadimm: Bad data type %d\n", t->type);
1355 exit(EXIT_FAILURE);
1356 }
1357 } else if (vr->parent != NULL) {
1358 struct vreg *vr2;
1359 struct decl *d2;
1360
1361 vr2 = get_parent_struct(vr);
1362 if ((d2 = vr2->var_backed) != NULL) {
1363 unsigned long off = calc_offsets(vr);
1364 #if 0
1365 hm continue here, upwards
1366 #endif
1367 if (d2->stack_addr) {
1368 /* XXX wow this sux */
1369 if (vr2->var_backed->stack_addr->is_func_arg) {
1370 vr2->var_backed->stack_addr->offset +=
1371 /*vr->memberdecl->offset*/ off;
1372 } else {
1373 vr2->var_backed->stack_addr->offset -=
1374 /*vr->memberdecl->offset*/ off;
1375 }
1376 do_stack(out, vr2->var_backed);
1377 if (vr2->var_backed->stack_addr->is_func_arg) {
1378 vr2->var_backed->stack_addr->offset -=
1379 /*vr->memberdecl->offset*/ off;
1380 } else {
1381 vr2->var_backed->stack_addr->offset +=
1382 /*vr->memberdecl->offset*/ off;
1383 }
1384 } else {
1385 /* static */
1386 x_fprintf(out, "%s+%lu",
1387 d2->dtype->name, calc_offsets(vr));
1388 needbracket = 0;
1389 }
1390 } else if (vr2->from_ptr) {
1391 /* Struct comes from pointer */
1392 x_fprintf(out, "%lu(%%%s",
1393 calc_offsets(vr) ,
1394 vr2->from_ptr->pregs[0]->name);
1395 } else {
1396 printf("BUG: Bad load for %s\n",
1397 vr->type->name? vr->type->name: "structure");
1398 abort();
1399 }
1400 } else if (vr->var_backed) {
1401 struct decl *d = vr->var_backed;
1402
1403 if (d->stack_addr != NULL) {
1404 do_stack(out, d);
1405 } else {
1406 /*
1407 * Static or register variable
1408 */
1409 if (d->dtype->storage == TOK_KEY_REGISTER) {
1410 unimpl();
1411 } else {
1412 if (d->dtype->tlist != NULL
1413 && d->dtype->tlist->type
1414 == TN_FUNCTION) {
1415 needbracket = 0;
1416 x_fprintf(out, "$%s", d->dtype->name);
1417 } else {
1418 x_fprintf(out, "%s(%%rip)", d->dtype->name);
1419 }
1420 needbracket = 0;
1421 }
1422 }
1423 } else if (vr->stack_addr) {
1424 /*
1425 * 07/26/12: This was missing support for writing through
1426 * the stack rather than frame pointer
1427 */
1428 if (vr->stack_addr->use_frame_pointer) {
1429 x_fprintf(out, "-%lu(%%rbp", vr->stack_addr->offset);
1430 } else {
1431 x_fprintf(out, "%lu(%%rsp", vr->stack_addr->offset);
1432 }
1433 } else if (vr->from_ptr) {
1434 x_fprintf(out, "(%%%s", vr->from_ptr->pregs[0]->name);
1435 } else {
1436 abort();
1437 }
1438 if (constant == NULL) {
1439 if (needbracket) {
1440 x_fputc(')', out);
1441 }
1442 }
1443 }
1444
1445 static void
emit_finish_program(void)1446 emit_finish_program(void) {
1447 /* x86_emit_gas.finish_program();*/
1448 }
1449
1450
1451 /* Mem to FPR */
1452 static void
emit_amd64_cvtsi2sd(struct icode_instr * ip)1453 emit_amd64_cvtsi2sd(struct icode_instr *ip) {
1454 x_fprintf(out, "\tcvtsi2sd ");
1455 print_mem_or_reg(ip->src_pregs[0], ip->src_vreg);
1456 x_fprintf(out, ", %%%s\n", ip->dest_pregs[0]->name);
1457 }
1458
1459 /* Mem to FPR */
1460 static void
emit_amd64_cvtsi2ss(struct icode_instr * ip)1461 emit_amd64_cvtsi2ss(struct icode_instr *ip) {
1462 x_fprintf(out, "\tcvtsi2ss ");
1463 print_mem_or_reg(ip->src_pregs[0], ip->src_vreg);
1464 x_fprintf(out, ", %%%s\n", ip->dest_pregs[0]->name);
1465 }
1466
1467 /* Mem to FPR */
1468 static void
emit_amd64_cvtsi2sdq(struct icode_instr * ip)1469 emit_amd64_cvtsi2sdq(struct icode_instr *ip) {
1470 x_fprintf(out, "\tcvtsi2sdq ");
1471 print_mem_or_reg(ip->src_pregs[0], ip->src_vreg);
1472 x_fprintf(out, ", %%%s\n", ip->dest_pregs[0]->name);
1473 }
1474
1475 /* Mem to FPR */
1476 static void
emit_amd64_cvtsi2ssq(struct icode_instr * ip)1477 emit_amd64_cvtsi2ssq(struct icode_instr *ip) {
1478 x_fprintf(out, "\tcvtsi2ssq ");
1479 print_mem_or_reg(ip->src_pregs[0], ip->src_vreg);
1480 x_fprintf(out, ", %%%s\n", ip->dest_pregs[0]->name);
1481 }
1482
1483 /* FPR to GPR */
1484 static void
emit_amd64_cvttsd2si(struct icode_instr * ip)1485 emit_amd64_cvttsd2si(struct icode_instr *ip) {
1486 x_fprintf(out, "\tcvttsd2si %%%s, %%%s\n",
1487 ip->src_pregs[0]->name, ip->dest_pregs[0]->name);
1488 }
1489
1490 /* FPR to GPR */
1491 /* 08/01/08: For quad-word target */
1492 static void
emit_amd64_cvttsd2siq(struct icode_instr * ip)1493 emit_amd64_cvttsd2siq(struct icode_instr *ip) {
1494 x_fprintf(out, "\tcvttsd2siq %%%s, %%%s\n",
1495 ip->src_pregs[0]->name, ip->dest_pregs[0]->name);
1496 }
1497
1498 /* FPR to GPR */
1499 static void
emit_amd64_cvttss2si(struct icode_instr * ip)1500 emit_amd64_cvttss2si(struct icode_instr *ip) {
1501 x_fprintf(out, "\tcvttss2si %%%s, %%%s\n",
1502 ip->src_pregs[0]->name, ip->dest_pregs[0]->name);
1503 }
1504
1505 /* FPR to GPR */
1506 /* 08/01/08: For quad-word target */
1507 static void
emit_amd64_cvttss2siq(struct icode_instr * ip)1508 emit_amd64_cvttss2siq(struct icode_instr *ip) {
1509 x_fprintf(out, "\tcvttss2siq %%%s, %%%s\n",
1510 ip->src_pregs[0]->name, ip->dest_pregs[0]->name);
1511 }
1512
1513 static void
emit_amd64_cvtsd2ss(struct icode_instr * ii)1514 emit_amd64_cvtsd2ss(struct icode_instr *ii) {
1515 struct reg *r = ii->dat;
1516
1517 x_fprintf(out, "\tcvtsd2ss %%%s, %%%s\n", r->name, r->name);
1518 }
1519
1520 static void
emit_amd64_cvtss2sd(struct icode_instr * ii)1521 emit_amd64_cvtss2sd(struct icode_instr *ii) {
1522 struct reg *r = ii->dat;
1523
1524 x_fprintf(out, "\tcvtss2sd %%%s, %%%s\n", r->name, r->name);
1525 }
1526
1527 static void
emit_amd64_load_negmask(struct icode_instr * ii)1528 emit_amd64_load_negmask(struct icode_instr *ii) {
1529 /* struct reg *r = ii->dat;*/
1530 struct amd64_negmask_data *dat = ii->dat;
1531 struct reg *target_fpr = dat->target_fpr;
1532 struct reg *support_gpr = dat->support_gpr;
1533 int for_double;
1534
1535 if (ii->src_vreg != NULL) {
1536 for_double = 1;
1537 } else {
1538 for_double = 0;
1539 }
1540
1541 if (sysflag == OS_OSX && backend->arch == ARCH_AMD64) {
1542 x_fprintf(out, "\tmovs%c _SSE_Negmask%s(%%rip), %%%s\n",
1543 for_double? 'd': 's',
1544 for_double? "_double": "",
1545 target_fpr->name);
1546 } else {
1547 if (picflag) {
1548 x_fprintf(out, "\tmov _SSE_Negmask%s@GOTPCREL(%%rip), %%%s\n",
1549 for_double? "_double": "",
1550 support_gpr->name);
1551 x_fprintf(out, "\tmovs%c (%%%s), %%%s\n",
1552 for_double? 'd': 's',
1553 support_gpr->name,
1554 target_fpr->name);
1555 } else {
1556 x_fprintf(out, "\tmovs%c (_SSE_Negmask%s), %%%s\n",
1557 for_double? 'd': 's',
1558 for_double? "_double": "",
1559 target_fpr->name);
1560 }
1561 }
1562 }
1563
1564 static void
emit_amd64_xorps(struct icode_instr * ii)1565 emit_amd64_xorps(struct icode_instr *ii) {
1566 struct reg *r = ii->dat;
1567
1568 x_fprintf(out, "\txorps %%%s, %%%s\n",
1569 r->name, ii->dest_vreg->pregs[0]->name);
1570 }
1571
1572 static void
emit_amd64_xorpd(struct icode_instr * ii)1573 emit_amd64_xorpd(struct icode_instr *ii) {
1574 struct reg *r = ii->dat;
1575
1576 x_fprintf(out, "\txorpd %%%s, %%%s\n",
1577 r->name, ii->dest_vreg->pregs[0]->name);
1578 }
1579
1580 static void
emit_amd64_ulong_to_float(struct icode_instr * ii)1581 emit_amd64_ulong_to_float(struct icode_instr *ii) {
1582 struct amd64_ulong_to_float *data = ii->dat;
1583 static unsigned long count;
1584
1585 if (data->code == TY_LDOUBLE) {
1586 x_fprintf(out, "\ttestq %%%s, %%%s\n", data->src_gpr->name, data->src_gpr->name);
1587 x_fprintf(out, "\tjs ._Ulong_float%lu\n", count);
1588 x_fprintf(out, "\tjmp ._Ulong_float%lu\n", count+1);
1589 x_fprintf(out, "._Ulong_float%lu:\n", count);
1590 x_fprintf(out, "\tfadds _Ulong_float_mask(%%rip)\n");
1591 x_fprintf(out, "._Ulong_float%lu:\n", count+1);
1592 count += 2;
1593 } else {
1594 x_fprintf(out, "\ttestq %%%s, %%%s\n", data->src_gpr->name, data->src_gpr->name);
1595 x_fprintf(out, "\tjs ._Ulong_float%lu\n", count);
1596 x_fprintf(out, "\tcvtsi2%sq %%%s, %%%s\n",
1597 data->code == TY_DOUBLE? "sd": "ss", data->src_gpr->name, data->dest_sse_reg->name);
1598 x_fprintf(out, "\tjmp ._Ulong_float%lu\n", count+1);
1599 x_fprintf(out, "._Ulong_float%lu:\n", count);
1600 x_fprintf(out, "\tmovq %%%s, %%%s\n", data->src_gpr->name, data->temp_gpr->name);
1601 x_fprintf(out, "\tandl $1, %%%s\n", data->src_gpr->composed_of[0]->name);
1602 x_fprintf(out, "\tshrq %%%s\n", data->temp_gpr->name);
1603 x_fprintf(out, "\torq %%%s, %%%s\n", data->src_gpr->name, data->temp_gpr->name);
1604 x_fprintf(out, "\tcvtsi2%sq %%%s, %%%s\n",
1605 data->code == TY_DOUBLE? "sd": "ss", data->temp_gpr->name, data->dest_sse_reg->name);
1606 x_fprintf(out, "\tadd%s %%%s, %%%s\n",
1607 data->code == TY_DOUBLE? "sd": "ss", data->dest_sse_reg->name, data->dest_sse_reg->name);
1608 x_fprintf(out, "._Ulong_float%lu:\n", count+1);
1609 count += 2;
1610 }
1611 }
1612
1613 struct emitter amd64_emit_gas = {
1614 0, /* need_explicit_extern_decls */
1615 init,
1616 emit_strings,
1617 emit_fp_constants,
1618 NULL, /* llong_constants */
1619 emit_support_buffers,
1620 NULL, /* pic_support */
1621
1622 NULL, /* support_decls */
1623 emit_extern_decls,
1624 emit_global_extern_decls,
1625 emit_global_static_decls,
1626 #if 0
1627 emit_global_decls,
1628 emit_static_decls,
1629 #endif
1630 emit_static_init_vars,
1631 emit_static_uninit_vars,
1632 emit_static_init_thread_vars,
1633 emit_static_uninit_thread_vars,
1634 NULL, /*emit_struct_defs,*/
1635 emit_comment,
1636 emit_dwarf2_line,
1637 emit_dwarf2_files,
1638 emit_inlineasm,
1639 emit_unimpl,
1640 emit_empty,
1641 emit_label,
1642 emit_call,
1643 emit_callindir,
1644 emit_func_header,
1645 emit_func_intro,
1646 emit_func_outro,
1647 emit_define,
1648 emit_push,
1649 emit_allocstack,
1650 emit_freestack,
1651 emit_adj_allocated,
1652 emit_inc,
1653 emit_dec,
1654 emit_load,
1655 emit_load_addrlabel,
1656 emit_comp_goto,
1657 emit_store,
1658 emit_setsection,
1659 emit_alloc,
1660 emit_neg,
1661 emit_sub,
1662 emit_add,
1663 emit_div,
1664 emit_mod,
1665 emit_mul,
1666 emit_shl,
1667 emit_shr,
1668 emit_or,
1669 NULL, /* emit_preg_or */
1670 emit_and,
1671 emit_xor,
1672 emit_not,
1673 emit_ret,
1674 emit_cmp,
1675 NULL, /* extend_sign */
1676 NULL, /* conv_fp */
1677 NULL, /* from_ldouble */
1678 NULL, /* to_ldouble */
1679 emit_branch,
1680 emit_mov,
1681 emit_setreg,
1682 emit_xchg,
1683 emit_addrof,
1684 NULL, /* initialize_pic */
1685 emit_copyinit,
1686 NULL, /* putstructregs */
1687 emit_copystruct,
1688 emit_intrinsic_memcpy,
1689 emit_zerostack,
1690 emit_alloca,
1691 emit_dealloca,
1692 emit_alloc_vla,
1693 emit_dealloc_vla,
1694 emit_put_vla_size,
1695 emit_retr_vla_size,
1696 emit_load_vla,
1697 emit_frame_address,
1698 emit_struct_inits,
1699 emit_save_ret_addr,
1700 emit_check_ret_addr,
1701 print_mem_operand,
1702 emit_finish_program,
1703 NULL, /* stupidtrace */
1704 NULL, /* finish_stupidtrace */
1705 };
1706
1707 struct emitter_amd64 emit_amd64_gas = {
1708 emit_amd64_cvtsi2sd,
1709 emit_amd64_cvtsi2ss,
1710 emit_amd64_cvtsi2sdq,
1711 emit_amd64_cvtsi2ssq,
1712 emit_amd64_cvttsd2si,
1713 emit_amd64_cvttsd2siq,
1714 emit_amd64_cvttss2si,
1715 emit_amd64_cvttss2siq,
1716 emit_amd64_cvtsd2ss,
1717 emit_amd64_cvtss2sd,
1718 emit_amd64_load_negmask,
1719 emit_amd64_xorps,
1720 emit_amd64_xorpd,
1721 emit_amd64_ulong_to_float
1722 };
1723
1724