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